프론트엔드/JS

[JavaScript] take 함수

턴태 2023. 5. 2. 07:31

Take 함수

const take = (l, iter) => {
  let res = [];
  for (const a of iter) {
    res.push(a);
    if (res.length === l) return res;
  }
  return res;
};

take 함수는 limit과 iterable 객체를 받아서 limit 개수 만큼 값을 저장하는 함수다.

 

그래서 range와 함께 5개의 원소만 뽑아내고자 한다면 다음과 같이 작성할 수 있다.

 

const range = l => {
  let i = -1;
  let res = [];
  while (++i < l) {
	    res.push(i);
    }
    return res;
};

const L = {};
L.range = function *(l) {
	let i = -1;
  while (++i < l) {
    yield i;
  }
};
console.log(take(5, range(100)));

take 함수는 이터러블 프로토콜을 따르고 있고, iterable을 꺼내서 push를 하는 단순한 함수다.

동일하게 L.range도 물론 사용이 가능하다.

console.log(take(5, L.range(100)));

range와 L.range의 차이는 값을 모두 평가한 다음 가져오느냐에 차이가 있다.

예를 들어서 1,000,000개의 원소를 가지는 리스트에서 5개의 원소만 가져온다고 할 때, range의 경우에는 1,000,000개의 원소를 모두 만들어 배열에 값을 평가하여 넣지만, L.range의 경우 5개만 받아서 처리한다는 점에서 효율성 차이가 발생한다.

 

console.time('');
take(5, range(1000000));
console.timeEnd('');

console.time('');
take(5, L.range(1000000));
console.timeEnd('');

: 15.193359375 ms
: 0.057861328125 ms

위와 같이 뚜렷한 차이를 보여준다.

 

또한, 아래의 표현은 무한 수열을 넣어도 되는데, 이는 어차피 5개의 값만 순회를 하기 때문이다. 반면 range의 경우는 불가하다.

이를 사용하는 이유는 배열의 길이가 어느 정도일지 모를 때, 원하는 시점만큼만 순회하고자 할 때 유용하게 사용할 수 있다.


드디어 제너레이터를 통해서 효율적인 코드를 작성하는 부분을 배웠다. 계속 제너레이터를 배우는 이유에 대해서 궁금증이 있었는데, 이렇게 제너레이터를 사용해 이터러블 객체를 반환하도록 하면, 값을 모두 평가하지 않고 next()로 순회하면서 필요할 때 값을 평가하기에 유용한 함수였다. 내가 어느 정도 길이의 배열을 사용하지 모르겠을 때, 조금 더 성능이 좋게 사용할 수 있다는 점에서 좋은 방법이라고 생각이 든다.

 

ㅊ출처: 인프런 함수형 프로그래밍과 JavaScript ES6+