for...in循环可以用来遍历对象的可枚举属性列表,但是如果遍历对象的值呢?

以数组为例,我们最基础的方式就是for循环:

var myArray = [1, 2, 3];
for (var i = 0; i < myArray.length; i++) {
    console.log(myArray[i]);
} 

// 1 2 3

事实上这种并不是真的遍历值,而是在遍历下标来获取到对应的值。

ES5新增了一些数组的遍历方法,比如:forEach(..)、every(..) 和 some(..);每种方法都可以接受一个回调函数并将其应用到数组每个元素上,,唯一的区别就是它们对于回调函数返回值的处理方式不同。

数组也可以使用for..in,不过得到的也是数组下标,在ES6的时候,新增了for...of的循环方法,用于遍历数组的值。

var myArray = [1, 2, 3];
for (var v of myArray) {
    console.log(v);
}
// 1
// 2
// 3

for..of 循环首先会向被访问对象请求一个迭代器对象,然后通过调用迭代器对象的next() 方法来遍历所有返回值。

而数组内置了@@iterator迭代器,所以for...of可以直接应用在数组上。

我们可以手动调用迭代器来实现遍历数组:

var myArray = [1, 2, 3];
var it = myArray[Symbol.iterator]()
it.next(); // { value:1, done:false } 
it.next(); // { value:2, done:false } 
it.next(); // { value:3, done:false } 
it.next(); // { done:true }

如你所见,调用迭代器的 next() 方法会返回形式为 { value: .. , done: .. } 的值,value 是当前的遍历值,done 是一个布尔值,表示是否还有可以遍历的值。

注意,和值“3”一起返回的是 done:false,乍一看好像很奇怪,你必须再调用一次next() 才能得到 done:true,从而确定完成遍历。这个机制和 ES6 中发生器函数的语义相关,不过已经超出了我们的讨论范围。

和数组不同,普通的对象是没有内置迭代器的,所以它无法直接通过for...of来实现遍历值。

但是我们可以自己手动添加一个迭代器来实现:

var myObject = {
    a: 2,
    b: 3
};

Object.defineProperty(myObject, Symbol.iterator, {
    enumerable: false,
    writable: false,
    configurable: true,
    value: function() {
        var o = this;
        var idx = 0;
        var ks = Object.keys(o);
        return {
            next: function() {
                return {
                    value: o[ks[idx++]],
                    done: (idx > ks.length)
                };
            }
        };
    }
});

// 手动遍历 myObject
var it = myObject[Symbol.iterator]();
it.next(); // { value:2, done:false } 
it.next(); // { value:3, done:false } 
it.next(); // { value:undefined, done:true }

// 用 for..of 遍历 myObject
for (var v of myObject) {
    console.log(v);
} 
// 2
// 3
分类: 你不知道的JavaScript 标签: for...of对象的遍历迭代器

评论

暂无评论数据

暂无评论数据

目录