본문 바로가기
Javascript

[ES6] for와 forEach, for...of / Spread... & ...Rest Operator

by kmmguumnn 2018. 3. 16.

어떤 반복적인 작업을 하고자 할 때, 우리는 for loop을 자주 활용한다.

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (let i = 0; i < digits.length; i++) {
  console.log(digits[i]);
}


한편 Javascript에서는 배열의 반복을 위한 forEach라는 메소드를 제공한다.

var donuts = ["jelly donut", "chocolate donut", "glazed donut"];

donuts.forEach(function(donut) {
  donut += " hole";
  donut = donut.toUpperCase();
  console.log(donut);
});

배열의 이름 뒤에 .forEach를 쓰고, 익명 함수의 매개변수에 들어가는 것이 배열의 각각의 원소로 작용하여 처음부터 끝까지 반복한다.



forEach 내부 익명함수의 매개변수를 3개 쓰는 경우도 있다. 각각 배열의 element, index, array를 의미한다. 이 순서를 맞춰줘야 하고, 이름은 어떻게 하든 상관없다.

words = ["cat", "in", "hat"];
words.forEach(function(word, num, all) {
  console.log("Word " + num + " in " + all.toString() + " is " + word);
});



그러나, forEach는 오직 배열에만 쓸 수 있는 메소드다. 또한 반복하는 도중에 멈출 수 있는 방법이 없다.

단지 배열만이 아니라, 어떤 반복적인 작업을 하고 싶을 때 쓸 수 있는 for 이외의 메소드가 또 있는데, for...of 다!

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const digit of digits) {
  console.log(digit);
}

어떻게 생겼는지 익혀두도록 하자. 배열의 이름과 of 앞의 인덱스 이름은 복수형-단수형으로 맞춰주는 것이 깔끔하다. 즉 위의 경우, digits 배열에서 digit을 하나씩 반복하는 형태로 직관적으로 이해할 수 있다.


const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const digit of digits) {
  if (digit % 2 === 0) {
    continue;
  }
  console.log(digit);
}

for...of는 이렇게 어떤 조건을 만족할 때 중간에 반복을 멈추거나 스킵할 수도 있다!



※ 참고로 for each...in 메소드는 deprecated 되었고, 구형 브라우저에서는 대부분 지원하지 않으니 쓰면 안된다! 

MDN for...of documentation






다음으로는 Spread Operator와 Rest Operator를 소개한다. 이 둘은 서로 기능면에서 대칭된다.


먼저, Spread Operator는 "iterable object"를 여러 개의 element로 확장시킨다. 예를 들면 배열을 여러 원소들로 spread, expand하는 것이다. 다음 코드를 보자.

const books = ["Don Quixote", "The Hobbit", "Alice in Wonderland", "Tale of Two Cities"];
console.log(...books);

이 코드를 수행하면, 배열이 출력되지 않고(문자열이 출력되지 않고), 


Don Quixote The Hobbit Alice in Wonderland Tale of Two Cities


이렇게 각 원소들이 하나의 개별적인 요소들로 따로 출력된다.



Rest Operator는 그 반대다. 여러 개의 요소들을 배열로 만들어 준다.

const order = [20.17, 18.67, 1.50, "cheese", "eggs", "milk", "bread"];
const [total, subtotal, tax, ...items] = order;
console.log(total, subtotal, tax, items);

destructuring을 이용해 total, subtotal, tax라는 이름의 변수에 숫자 3개를 저장하고, 나머지는 ...items라고 처리하고 있다. order 배열에 남아 있는 나머지 요소들을 하나의 배열로 만들어 그곳에 저장한다. 위의 경우 그 배열의 이름이 item이다. 위 코드를 수행하면 다음과 같이 출력된다.

20.17 18.67 1.5 ["cheese", "eggs", "milk", "bread"]



Rest Operator의 경우 Variadic functions, 즉 매개변수의 개수가 고정되어 있지 않은 함수에서 효과적이다.

받은 매개변수들의 합을 계산하는 sum()이라는 함수가 있다고 하자. 매개변수가 몇 개가 들어올지는 모른다. Rest Operator없이 구현하려면 다음과 같이 해야할 것이다.

function sum() {
  let total = 0;  
  for(const argument of arguments) {
    total += argument;
  }
  return total;
}

argument object라는 것을 활용한 방법인데, 일단 argument object가 뭔지 모르면 코드가 잘 이해되지 않을 뿐만 아니라, 얼핏 보면 sum() 함수를 매개변수가 없는 함수로 오해할 수 있다. 하지만 Rest Operator를 활용하면 다음과 같이 깔끔하게 함수를 정의할 수 있다!

function sum(...nums) {
  let total = 0;  
  for(const num of nums) {
    total += num;
  }
  return total;
}

Rest Operator와 for...of 메소드가 적절히 사용되었다.

댓글