2019-07-06 TIL

2019-07-06

JavaScript Array의 forEach() vs Map()

회사에서 기존에 작성된 코드를 보던 중, iteration 목적으로 Array.prototype.map()메서드를 사용하는 것을 보고 혹시 성능상의 이유가 있는지 조금 궁금해져 찾아봄.

이 글의 결론

  1. forEachmap은 서로 상호 호환 가능하다.
  2. map은 메모리를 할당해 콜백의 return값을 저장한다. 반면 forEach는 return을 무시하고 항상 undefined를 리턴한다.
  3. map은 새 어레이를 리턴하는 반면, forEach는 콜백 함수로 하여금 현재 어레이를 변형(mutate)할 수 있도록 한다.

흔히 알려진 대로다.

그런데 jsben.ch에서 빈 어레이에 오브젝트를 push하는 동일한 코드를 forEachmap을 이용해 1만 회 iteration 해보니 forEach가 약 10% 더 빨랐다.

jsperf에서 수행한 본문의 테스트를 jsbench에서 돌리면 역시 forEach가 더 빨랐다. 약 5%.

이렇게 테스팅 환경에 따라 결과가 다를 수 있으며, 유의미한 차이는 없으니 좀 더 의미있는 차이에 집중하는 것이 좋겠다.

Array.from() 메서드

MDN

이런 게 있네. MDN Array methods 맨 위에 있는데 몰랐다. Array.prototype.from()이 아님에 주의하자.

Array.from(arrayLike[, mapFn[, thisArg]])
  • Array-like를 첫 번째 인자로 받아 새 Array를 리턴한다.

    첫 번째 인자는 Array-like 말고 iterable object도 가능하다.

  • 두 번째 인자로 map을 수행할 수 있는 함수를 받는다!

    Array.from().map() 을 한 것과 결과는 같지만, 중간 부산물? 어레이가 만들어진다는 차이가 있다. 이건 typedArray처럼 특정 어레이 서브클래스를 다룰 때 특별히 중요하다고 한다. (중간 어레이는 타입에 맞추기 위해 부득이하게 잘린 값이 들어갈 수 있다.)

이런 말도 적혀있다.

ES6에서, class 문법으로 인해 built-in, user-defined 클래스 둘 다 sub-classing이 가능해졌기 때문에 Array.from같은 static 메서드들이 Array의 서브클래스로 상속된다. 그리고 Array가 아닌 Array의 서브클래스의 새 인스턴스를 만든다.

그리고 이거 좀 신기하다.

// Generate a sequence of numbers
// Since the array is initialized with `undefined` on each position,
// the value of `v` below will be `undefined`
Array.from({length: 5}, (v, i) => i);
// [0, 1, 2, 3, 4]

위 방법을 이용해 range 함수를 만들 수도 있다.

// Sequence generator function (commonly referred to as "range", e.g. Clojure, PHP etc)
const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));

// Generate numbers range 0..4
range(0, 4, 1);
// [0, 1, 2, 3, 4] 

// Generate numbers range 1..10 with step of 2 
range(1, 10, 2); 
// [1, 3, 5, 7, 9]

// Generate the alphabet using Array.from making use of it being ordered as a sequence
range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x));
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

그리고 Array.from()은 ES6에 추가된 메서드다.


Minchang Kim
Minchang Kim
웹/앱 개발자 김민창입니다! 좋은 하루 되세요!