본문으로 바로가기
반응형

기존 자바스크립트(JavaScript)에서는 배열 혹은 객체에 대한 복잡한 처리를 위해서 Underscore 또는 Lodash와 같은 라이브러리를 많이 사용해왔습니다. 그러나 최근의 브라우저에서 ES5, ES6와 같은 최신 스펙을 지원하기 시작하면서, 배열 처리를 위한 다양한 메소드들을 사용할 수 있게 되었습니다. 

이번 글에서는 ES5에서 지원하는 Array Method map, filter, forEach에 대해서 살펴보겠습니다. 이 메소드들을 잘 사용하면 for loop를 사용하는 경우보다 훨씬 깔끔하고 가독성 높은 코드를 얻을 수 있습니다.

 

1. Array.prototype.map()

  • Map() 메소드는 배열의 각각의 요소에 대하여 순차적으로 주어진 함수를 실행한 반환 값을 모아 새로운 배열을 반환합니다.
  • Callback 함수에서 값을 변경하지 않는 이상 기존 배열 값은 변경되지 않습니다. 

[문법]

arr.map(function(currentValue, index, array), thisValue))

 

Parameter Description
function

(필수) 배열의 각 값에 대해 실행할 함수 (총 3개 인자)

   - currentValue (필수) 배열내에서 순차적으로 입력되는 엘리먼트
   - index (옵션) 현재 엘리먼트의 배열 내 index
   - array (옵션) 현재 엘리먼트가 속한 배열
thisValue (옵션) 함수 내부에서 사용될 this에 대한 값

[예제]

먼저 배열의 각 엘리먼트의 값을 2배로 해주는 함수를 구현해 본다고 하겠습니다. 기존의 일반적인 방식으로 이를 구현하면 보통, 아래와 같이 고려할 수 있습니다.

var arr = [1,2,3,4,5];
var mapped = [];
for (let i=0; i<arr.length; i++) {
  mapped.push(arr[i] * 2);
}

console.log(mapped); // [2,4,6,8,10]

 

이제, 이를 map()을 이용하여 표현해 보겠습니다. 다른 메소드 들과 공통되는 부분도 많으므로, map에 대해서는 대표적으로 다양한 표현식을 사용해서 살펴보도록 보겠습니다. 

 

✅  map 사용 예제

map을 사용하여 한 줄로 간단하게 작성할 수 있습니다.

var arr = [1,2,3,4,5];
var mapped = arr.map(function(item) { return item*2; });

console.log(mapped); // [2,4,6,8,10]

 

✅  콜백을 외부 함수로 구현

만약, map 내의 함수에서 해야 할 일이 많다면 외부 함수로 구현하는 것이 더 좋아 보입니다.

var arr = [1,2,3,4,5];
var mapped = arr.map(multBy2);

function multBy2(item) {
  return item*2;
}

console.log(mapped); // [2,4,6,8,10]

 

✅  화살표 함수 사용 간략화 버전

화살표 함수를 쓰면 한결 더 깔끔해지네요!

var arr = [1,2,3,4,5];
var mapped = arr.map((item) => item*2);
console.log(mapped); // [2,4,6,8,10]

 

✅  Index의 사용 예

만약, 5개의 엘리먼트 중 홀수번째 엘리먼트만 2배의 값으로 해주고 싶다면 index를 이용하면 됩니다.

var arr = [1,2,3,4,5];
// 홀수번째 요소(0부터 시작한다고 할 때 1, 3번 값)만 x2
arrIdx = arr.map((item, index) => (index%2===0)?item:item*2);
console.log(arrIdx); // [1, 4, 3, 8, 5]

 

✅  This 인자 주입

map 내부 callback 함수에서 사용할 this를 주입해서 사용할 수 있습니다.

아래는 객체 내부에서 객체의 프로퍼티(factor)를 사용해야 할 때 this를 주입하는 방법입니다. 

var obj = {
  factor: 2,
  arr: [1, 2, 3],
  mult: function() {
    return this.arr.map(function(item) {      
      return item * this.factor
    }, this)
  }  
}

console.log(obj.mult()) // [2,4,6]

obj.factor = 3;
console.log(obj.mult()) // [3,6,9]

 

위의 결과는 bind(this) 또는 화살표 함수를 사용하는 효과를 가져옵니다.

var obj = {
  factor: 2,
  arr: [1, 2, 3],
  multBind: function() {
    return this.arr.map(function(item) {      
      return item * this.factor
    }.bind(this))
  },
  multArrow: function() {
    return this.arr.map((item) => {return item * this.factor})
  } 
}

console.log(obj.multBind()) // [2,4,6]
console.log(obj.multArrow()) // [2,4,6]

obj.factor = 3;
console.log(obj.multBind()) // [3,6,9]
console.log(obj.multArrow()) // [3,6,9]

 

 

 

이와 같이 map 메소드를 이용하면 기존의 코드를 간략화하면서도 가독성 높게 표현할 수 있습니다. 약간만 응용하면 다양한 작업을 할 있습니다. 예를 들어, 객체 배열에서 일부 key에 해당하는 값만 가져와서 배열을 구성할 수 있습니다. 

// object array의 name key에 해당하는 값만 배열로 표시
var objArr = [{name: '철수', age: 10},{name: '영희', age: 10}, {name: '바둑이', age: 2}]

var nameArr = objArr.map((item)=> item.name);
console.log(nameArr) // ["철수", "영희", "바둑이"]

 

2. Array.prototype.filter()

  • Filter() 메소드는 주어진 함수가 true를 반환하는 경우의 엘리먼트만 포함하는 새로운 배열을 생성합니다.
  • 원본 배열은 변경되지 않습니다.

[문법]

arr.filter(function(currentValue, index, array), thisValue))

* 인자에 대한 설명은 Array.prototype.map 참조

[예제]

다음 예제는 배열에서 홀수, 짝수를 분리하여 각각의 배열을 생성하는 예제입니다. Filter 메소드를 이용하면 쉽게 구현할 수 있습니다.

var arr = [1,2,3,4,5]
var odd = arr.filter((item)=> item%2 === 1 );
var even = arr.filter((item)=> item%2 === 0 );
console.log(odd); // [1,3,5]
console.log(even); // [2,4]

 

[객체 배열에서의 사용]

물론 객체 배열 (Object Array)에서도 잘 동작합니다.

앞의 "철수, 영희, 바둑이" 예제에서 5살 이상의 항목만 걸러내어 새로운 배열을 생성해보겠습니다.

var objArr = [{name: '철수', age: 10},{name: '영희', age: 10}, {name: '바둑이', age: 2}]

var over5 = objArr.filter((item)=> item.age>5);
console.log(over5) // [{name: '철수', age: 10},{name: '영희', age: 10}]

 

[filter + map]

반환 값이 배열이므로 다른 배열 메소드와 연결하여 사용할 수 있습니다. 아래는 filter와 map을 동시에 사용하는 예제입니다.

var objArr = [{name: '철수', age: 10},{name: '영희', age: 10}, {name: '바둑이', age: 2}]

// 5살 이상인 요소의 이름만 배열로 저장
var nameArr = objArr.filter((item)=> item.age>5).map((item)=> item.name);
console.log(nameArr) // ["철수", "영희"]

 

많은 연산을 필요로 하지 않는 간단한 data라면 가독성을 위해서 이와 같이 체이닝을 통해서 구현해도 좋을 것 같습니다. 

 

3. Array.prototype.forEach()

  • forEach()는 배열에 있는 각각의 요소에 대해 한 번씩 callback 함수를 실행합니다.
  • 함수 내에서 변경하지 않는 이상 기존 배열 값은 변경되지 않습니다.

[문법]

arr.forEach(function(currentValue, index, array), thisValue))

* 인자에 대한 설명은 Array.prototype.map 참조

[예제]

단순하게는 기존 반복문을 편리하게 대체할 수 있는 기능이라고 생각하면 쉬울 것 같습니다. 아래는 forEach()를 이용하여 배열의 합을 구하는 예제입니다. 기존의 for loop 보다는 확실히 깔끔해 보입니다.

var arr = [1,2,3,4,5]

// 기존 foor loop
var sum = 0;
for (let i=0; i<arr.length; i++) {
  sum += arr[i];
}
console.log(sum); // 15

// forEach()
var sum = 0;
arr.forEach((item) => sum +=item);

console.log(sum); // 15

 

반응형