(一)原生迭代器原理
// 原生迭代器原理
function createIterator(items) {
var i = 0;
return {
next: function () {
var done = i >= items.length;
var val = !done ? items[i++] : undefined;
return {
done: done,
value: val
}
}
}
}
复制代码
(二)for-of详解
-
for of 遍历的是obj[Symbol.iterator]这个属性
-
具有这个属性能被for-of遍历的有
- 数组
- Set
- Map
- 类数组(例如arguments属性)
- 字符串
- Generator对象
-
自己实现一个for-of函数
function forOf(obj, cb) {
let iterable, result;
// 如果传入对象Symbol.iterator属性类型不是function,抛出错误
if (typeof obj[Symbol.iterator] !== "function") {
throw new TypeError(result + 'is not iterable');
}
iterable = obj[Symbol.iterator]()
result = iterable.next();
while (!result.done) {
cb(result.value)
result = iterable.next();
}
}
// 开始调用自己的forOf
forOf([1, 2, 3], (item) => {
console.log(item);//1,2,3
})
复制代码
-
往数组添加可被for-of遍历的属性
arr.name = 'e';
人为添加数组上面的属性,这个属性去不到Symbol.iterator属性上
Array.prototype.d = 'f'
往原型添加也无法用for of遍历到这个属性
arr.push('d');
push方法添加的属性可以用for of遍历
(三)for-in详解
-
和for-of不同,用原型和用arr.name = 'e'这种方法添加属性,for-in可以遍历到这样添加的属性,毫无疑问push方法添加也可以
-
用for-in遍历得到结果的顺序
function Foo() {
this[100] = 'test-100'
this[1] = 'test-1'
this['b'] = 'test-b'
this[50] = 'test-50'
this[9] = 'test-9'
this[8] = 'test-8'
this[3] = 'test-3'
this[5] = 'test-5'
this['A'] = 'test-A'
this['C'] = 'test-C'
}
let bar = new Foo();
for (let key in bar) {
console.log(`index:${key} value:${bar[key]} `);
}
// 遍历顺序如下:
// index:1 value:test-1
// index:3 value:test-3
// index:5 value:test-5
// index:8 value:test-8
// index:9 value:test-9
// index:50 value:test-50
// index:100 value:test-100
// index:b value:test-b
// index:A value:test-A
// index:C value:test-C
复制代码
我们也能发现,for in遍历得到的是键名,不是键值
(四)总结
for-in特点
- 循环返回的是数据结构的键名
- 遍历数组返回的是数组的下标
- 不仅可以遍历已有的值,还可以遍历原型上的键,以及手动添加的键
- 特殊情况下,遍历的顺序不会按照对象的属性进行
for of特点
- 不能遍历对象(没有Symbol.iterator属性的数据结构)
- 遍历数组返回的是元素