본문으로 건너뛰기

for...of 루프_ES6 노트 1

무료2016-03-13#JS#ES6 for-of#js for-of#ES6 forof#ES6 forof循环

for...of 는 배열 순회에 사용되며, for...in 으로 객체를 순회하는 것과 유사합니다

一。역할

배열 순회에 사용되며, for...in 으로 객체를 순회하는 것과 유사합니다

for (var i = 0; i < arr.length; i++) 는 사용하기 좋지만, 귀찮을 경우 arr.forEach() 를 사용할 수도 있습니다. 그렇다면 for...in 이 존재하는 의미는 무엇일까요?

  1. for (var i = 0; i < arr.length; i++) 는 간결하지 않습니다

너무 깁니다. 길면 실수하기 쉽습니다. 예를 들어 필자가 자주 범하는 실수: for (var j = 0; j < arr[i].length; i++)

  1. forEach 는 유연성이 부족합니다

arr.forEach 는 사용하기 어렵습니다. break 또는 return 으로 빠져나올 수 없기 때문입니다

  1. for...in 은 배열 순회에는 적합하지 않습니다

for...in 은 커스텀 속성뿐만 아니라 프로토타입 속성까지 순회하고, index 는 숫자가 아닌 문자열이며, 경우에 따라서는 순서대로 순회하지 않기도 합니다

따라서, for...in 으로 객체를 순회하는 것처럼 간단하고 사용하기 쉬운, 배열을 순회하는 더 편리한 방법이 필요합니다. 그것이 바로 for...of 입니다

二。특징

###1.다른 컬렉션도 순회 가능

배열뿐만 아니라 다른 컬렉션 (iterable) 도 순회할 수 있습니다. NodeList/arguments, 문자열, Map, Set 등을 포함합니다

샘플 코드는 다음과 같습니다:

// 배열
var arr = [1, 2, 2, 4];
for (var val of arr) {
    console.log(val);
}
// 배열 유사 객체 (arguments, NodeList)
(function() {
    for (var val of arguments) {
        console.log(val);
    }
})(1, 2, 4);
// Set
var uniqueArr = new Set(arr);   // Set 자동 중복 제거
for (var val of uniqueArr) {
    console.log(val);
}
// Map
var map = new Map([['a', 1], ['b', 2]]);
map.set('c', 3);
for (var [key, val] of map) {
    console.log('map[' + key + '] = ' + val);
}

주의: Chrome47 은 var [key, val] of map 구문을 지원하지 않습니다. FF43 은 지원합니다. node --harmony v0.12.7 은 구조 분해 할당 식을 지원하지 않습니다. ES6 를 편안하게체험하고 싶다면, node 에 think.js 를 설치하는 것을 권장합니다

###2.객체는 순회 불가

for...of 는 객체 순회를 지원하지 않지만, [Symbol.iterator]() 메서드를 추가하여 다른 객체 (예를 들어 jQuery 객체) 가 for...of 순회를 지원하도록 할 수 있습니다. [Symbol.iterator]() 메서드가 있는 객체는 반복 가능합니다 (iterable)

어떻게 지원하지 않는지? 샘플 코드는 다음과 같습니다:

var obj = {
    'a': 1,
    'b': 2
}

for (var val of obj) {
    console.log(val);
}
// Uncaught TypeError:  is not a function
// 에러, 객체 순회를 지원하지 않습니다. 그것은 for...in 의 역할입니다

커스텀 객체가 for...of 순회를 지원하도록 하려면, [Symbol.iterator]() 메서드를 추가해야 합니다. 다음과 같이:

// 일반 메서드로 이터레이터 구현
class MyIterator {
    constructor(obj) {
        this.obj = obj;
        this.keys = Object.keys(obj);
        this.index = 0;
    }

    // iterator 인터페이스 구현
    [Symbol.iterator]() {
        return this;
    }
    next() {
        var val = this.obj[this.keys[this.index]];
        if (this.index === this.keys.length) {
            return {
                done: true
            }
        }
        else {
            this.index++;
            return {
                done: false,
                value: val
            }
        }
    }
}
// 테스트
var _obj = {
    a: 2,
    b: 1
}
for (var val of new MyIterator(_obj)) {
    console.log(val);
}

잠깐, Symbol 이란 무엇일까요? Symbol 에는 큰 유래가 있습니다: Symbol 은 js 의제 7 번째기본 타입입니다 (원래 있던 6 개는 null, undefined, Number, Boolean, Object, String). 문자열도 객체도 아닙니다. 증거는 다음과 같습니다:

typeof Symbol() === 'symbol'

위 코드에 나타난 Symbol.iterator 는 빌트인 함수명입니다 (Symbol 타입이며, 일반 함수명은 String). for...of 문을 실행할 때, 인터프리터는 of后面的 객체에서 Symbol.iterator 라는 이름의 메서드를 찾습니다. 해당 메서드 실행 후 이터레이터 객체 iterator 를 반환합니다. iterator 를 얻은 후 당연히 .next(), .next() 하고 done 까지 호출합니다. 과정은 다음과 같습니다:

// 배열
var arr = [1, 2, 2, 4];
// for (var val of arr) {
//     console.log(val);
// }
var iter = arr[Symbol.iterator]();
while (true) {
    var res = iter.next();
    if (res.done) {
        break;
    }
    else {
        var val = res.value;
        console.log(val);
    }
}

물론, 우리의 이 기능은 너무 약합니다. for...of 의 강력한 점은 break, continue, return 을 지원하는 것으로, 고전적인 for 루프와 같습니다

###3.커스텀 이터레이터 지원

사실 위에서 이미 커스텀 이터레이터를 구현했지만, 귀찮은 것 같습니다. 이것을 쓰느니 차라리 죽는 게 낫습니다. ES6 표준을 제정한 사람도 당연히 이를 고려했습니다. generator 구문 (function* + yield) 과 조합하면 쉽게 커스텀 이터레이터를 구현하여 for...of 순회를 지원할 수 있습니다:

var obj = {
    'a': 1,
    'b': 2
}
// generator 로 이터레이터 구현
obj[Symbol.iterator] = function*() {
    for (var key in this) {
        yield this[key];
    }
}
for (var val of obj) {
    console.log(val);
}

순식간에 이터레이터를 구현했습니다. 이제 훨씬 편리해졌습니다

P.S. 사실 우리의 MyIterator 는 엄밀히 말하면 generator 입니다. (이터레이터의) 제네레이터입니다

三。요약

ES5 는 forEach 를 도입했지만, 실제로는 별로 쓸모가 없습니다. 많은 경우, 작성한 forEach 를 고전적인 for 루프로 바꿔야 합니다..forEach 는 유연성 측면에서 every 에 못 미치지만, every 는 새로운 배열을 생성합니다..

好了, 이제 for...of 가 생겼습니다. forEach 와는 작별입니다

###참고 자료

  • 《ES6 in Depth》: InfoQ 中文站에서 제공하는 무료 전자책

댓글

아직 댓글이 없습니다

댓글 작성