Open YBFACC opened 4 years ago
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作
Iterator
平常使用的(...)扩展运算符和 for...of... 都在隐式的调用的 Iterator 。
(...)扩展运算符
for...of...
原生具备 Iterator 接口。
Array Map Set String TypedArray 函数的 arguments 对象 NodeList 对象
已经存在的Symbol.iterator具有以下特性
Symbol.iterator
let obj = { data: [1, 2, 3], [Symbol.iterator]: function () { let context = this let index = 0 let length = this.data.length return { next: function () { if (index < length) { return { value: context.data[index++], done: false } } else { return { value: void 0, done: true } } } } } } for (const item of obj) { console.log(item)//1 2 3 }
原本你不可以直接在对象上使用for...of... 。现在我们在对象上定义[Symbol.iterator],使得for...of... 可以找到 iterator属性进行遍历。
[Symbol.iterator]
iterator
for...of... 可以约等于以下代码:
let iterator = obj[Symbol.iterator]() let result = iterator.next() while (!result.done) { console.log(result.value) //.... result = iterator.next() }
我们不可以更改对象原型链上的 Symbol.iterator ,只能在当前对象上定义新的 Symbol.iterator。
例如以下例子:
let a = [1, 2, 3] a[Symbol.iterator] = function () { let conext = this let index = 0 return { next() { if (Number.isInteger(conext[index])) { return { value: conext[index++] + 1, done: false } } else { return { value: void 0, done: true } } } } } for (const item of a) { console.log(item)//2 3 4 }
扩展运算符也是调用 Symbol.iterator。
let a = [1, 2, 3] a[Symbol.iterator] = function () { let conext = this let index = 0 return { next() { if (Number.isInteger(conext[index])) { return { value: conext[index++] + 1, done: false } } else { return { value: void 0, done: true } } } } } let b = [...a] //[2,3,4]
return() 用于循环提前结束的情况。
return()
return方法必须返回一个对象,这是 Generator 规格决定的。
return
let a = [1, 2, 3] a[Symbol.iterator] = function () { let conext = this let index = 0 return { next() { if (Number.isInteger(conext[index])) { return { value: conext[index++] + 1, done: false } } else { return { value: void 0, done: true } } }, return() { console.log('提前结束') return { value: void 0, done: true } } } } for (const item of a) { console.log(item) break } for (const item of a) { console.log(item) throw new Error() }
throw() 用于配合 Generator 函数使用。
throw()
Generator 函数
var g = function* () { try { yield 123 } catch (e) { console.log('内部捕获', e) } } var i = g() console.log(i.next()) try { i.throw('a') i.throw('b') } catch (e) { console.log('外部捕获', e) }
let a = 'abc' for (const item of a) { console.log(item) } //a b c
这里的string是字面量,本身没有Symbol.iterator,这里应该是隐式字面量转化为String包装类,包装类上就有Symbol.iterator,符合预期。
let a = 'abc' let A = new String(a) for (const item of A) { console.log(item) } //a b c
引用和部分代码都来自:ECMAScript 6 入门
遍历器
平常使用的
(...)扩展运算符
和for...of...
都在隐式的调用的Iterator
。原生具备
Iterator
接口。已经存在的
Symbol.iterator
具有以下特性自己实现一个Iterator
原本你不可以直接在对象上使用
for...of...
。现在我们在对象上定义[Symbol.iterator]
,使得for...of...
可以找到iterator
属性进行遍历。for...of...
for...of...
可以约等于以下代码:覆盖原有的Symbol.iterator
我们不可以更改对象原型链上的
Symbol.iterator
,只能在当前对象上定义新的Symbol.iterator
。例如以下例子:
扩展运算符
扩展运算符也是调用
Symbol.iterator
。return()和 throw()
return()
用于循环提前结束的情况。throw()
用于配合Generator 函数
使用。关于String的补充
这里的string是字面量,本身没有
Symbol.iterator
,这里应该是隐式字面量转化为String包装类,包装类上就有Symbol.iterator
,符合预期。参考
引用和部分代码都来自:ECMAScript 6 入门