We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Iterable
for...of
可迭代(Iterable) 对象是数组的泛化。这个概念是说任何对象都可以被定制为可在 for..of 循环中使用的对象。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,下面将一个普通对象转化为可迭代对象:
for..of
Iterator
Symbol.iterator
// 比如一个 `range` 对象,它代表了一个数字区间: const range = { from: 1, to: 5, }; // 我们希望 for..of 这样运行: // for(let num of range) ... num=1,2,3,4,5 // 1. for..of 调用首先会调用这个: range[Symbol.iterator] = function () { // ……它返回迭代器对象(iterator object): // 2. 接下来,for..of 仅与此迭代器一起工作,要求它提供下一个值 return { current: this.from, last: this.to, // 3. next() 在 for..of 的每一轮循环迭代中被调用 next() { // 4. 它将会返回 {done:.., value :...} 格式的对象 if (this.current <= this.last) { return { done: false, value: this.current++ }; } else { return { done: true }; } }, }; }; // 现在它可以运行了! for (let num of range) { console.log(num); // 依次输出 1, 2, 3, 4, 5 }
为了让 range 对象可迭代(也就让 for..of 可以运行)我们需要为对象添加一个名为 Symbol.iterator 的方法(一个专门用于使对象可迭代的内置 symbol)。
range
next
next()
{done: Boolean, value: any}
done=true
value
请注意可迭代对象的核心功能:关注点分离。
range[Symbol.iterator]()
因此,迭代器对象和与其进行迭代的对象是分开的。
从技术上说,我们可以将它们合并,并使用 range 自身作为迭代器来简化代码:
const range = { from: 1, to: 5, [Symbol.iterator]() { this.current = this.from; return this; }, next() { if (this.current <= this.to) { return { done: false, value: this.current++ }; } else { return { done: true }; } }, };
现在 range[Symbol.iterator]() 返回的是 range 对象自身:它包括了必需的 next() 方法,并通过 this.current 记忆了当前的迭代进程。这样更短,对吗?是的。有时这样也可以。
this.current
但缺点是,现在不可能同时在对象上运行两个 for..of 循环了:它们将共享迭代状态,因为只有一个迭代器,即对象本身。但是两个并行的 for..of 是很罕见的,即使在异步情况下。
原生具备 Iterator 接口的数据结构如下:
Array
Map
Set
String
TypedArray
arguments
NodeList
对于一个字符串,for..of 遍历它的每个字符:
for (let char of 'test') { // 触发 4 次,每个字符一次 console.log(char); // t, then e, then s, then t } // 对于Unicode字符 for (let char of '𝒳😂') { console.log(char); // 𝒳,然后是 😂 }
const str = 'Hello'; // 和 for..of 做相同的事 // for (let char of str) console.log(char); const iterator = str[Symbol.iterator](); while (true) { const result = iterator.next(); if (result.done) break; console.log(result.value); // 一个接一个地输出字符 }
显式调用迭代器比使用 for..of 更能精细控制迭代过程。例如,我们可以拆分迭代过程:迭代一部分,然后停止,做一些其他处理,然后再恢复迭代。
有两个看起来很相似,但又有很大不同的正式术语。请你确保正确地掌握它们,以免造成混淆。
length
实际任务中我们可能会遇到可迭代对象或类数组对象,或两者兼有。例如,字符串即是可迭代的(for..of 对它们有效),又是类数组的(它们有数值索引和 length 属性)。但是一个可迭代对象也许不是类数组对象。反之亦然,类数组对象可能不可迭代。
可迭代对象和类数组对象通常都 不是数组,它们没有 push 和 pop 等方法。如果我们有一个这样的对象,并想像数组那样操作它,就可以通过一些其他方法将其转化为数组。
push
pop
const arr = Array.from({ 0: 'Hello', 1: 'World', length: 2, }); console.log(arr.pop()); // World(pop 方法有效) // range 来自上文的例子中 console.log(Array.from(range).toString()); // 1,2,3,4,5
另外用Array.from处理带 Unicode 的字符是非常方便的,与 str.split 方法不同,它依赖于字符串的可迭代特性。
Array.from
str.split
可以基于 Array.from 创建 UTF-16 扩展字符的slice 方法:
slice
const slice(str, start, end) => Array.from(str).slice(start, end).join(''); const str = '𝒳😂𩷶'; console.log(slice(str, 1, 3)); // 😂𩷶 // 原生方法不支持识别UTF-16 扩展字符 console.log( str.slice(1, 3) ); // "\udcb3\ud83d"(两个不同 UTF-16 扩展字符碎片拼接的结果)
另外解构也是类似原理:
console.log([...'𝒳😂𩷶']); // => ["𝒳", "😂", "𩷶"]
The text was updated successfully, but these errors were encountered:
No branches or pull requests
Iterable
/for...of
可迭代(Iterable) 对象是数组的泛化。这个概念是说任何对象都可以被定制为可在
for..of
循环中使用的对象。当使用for...of
循环遍历某种数据结构时,该循环会自动去寻找Iterator
接口。ES6 规定,默认的Iterator
接口部署在数据结构的Symbol.iterator
属性,下面将一个普通对象转化为可迭代对象:为了让
range
对象可迭代(也就让for..of
可以运行)我们需要为对象添加一个名为Symbol.iterator
的方法(一个专门用于使对象可迭代的内置 symbol)。for..of
循环启动时,它会调用这个方法(如果没找到,就会报错)。这个方法必须返回一个 迭代器(iterator) —— 一个有next
方法的对象。for..of
仅适用于这个被返回的对象。for..of
循环希望取得下一个数值,它就调用这个对象的next()
方法。next()
方法返回的结果的格式必须是{done: Boolean, value: any}
,当done=true
时,表示迭代结束,否则value
是下一个值。请注意可迭代对象的核心功能:关注点分离。
range
自身没有next()
方法。range[Symbol.iterator]()
创建了另一个对象,即所谓的“迭代器”对象,并且它的next
会为迭代生成值。因此,迭代器对象和与其进行迭代的对象是分开的。
从技术上说,我们可以将它们合并,并使用
range
自身作为迭代器来简化代码:现在
range[Symbol.iterator]()
返回的是range
对象自身:它包括了必需的next()
方法,并通过this.current
记忆了当前的迭代进程。这样更短,对吗?是的。有时这样也可以。但缺点是,现在不可能同时在对象上运行两个
for..of
循环了:它们将共享迭代状态,因为只有一个迭代器,即对象本身。但是两个并行的for..of
是很罕见的,即使在异步情况下。原生具备
Iterator
接口的数据结构如下:Array
Map
Set
String
TypedArray
arguments
对象NodeList
对象对于一个字符串,
for..of
遍历它的每个字符:显式调用迭代器
显式调用迭代器比使用
for..of
更能精细控制迭代过程。例如,我们可以拆分迭代过程:迭代一部分,然后停止,做一些其他处理,然后再恢复迭代。可迭代(iterable)和类数组(array-like)
有两个看起来很相似,但又有很大不同的正式术语。请你确保正确地掌握它们,以免造成混淆。
Symbol.iterator
方法的对象。length
属性的对象,所以它们看起来很像数组。实际任务中我们可能会遇到可迭代对象或类数组对象,或两者兼有。例如,字符串即是可迭代的(
for..of
对它们有效),又是类数组的(它们有数值索引和length
属性)。但是一个可迭代对象也许不是类数组对象。反之亦然,类数组对象可能不可迭代。可迭代对象和类数组对象通常都 不是数组,它们没有
push
和pop
等方法。如果我们有一个这样的对象,并想像数组那样操作它,就可以通过一些其他方法将其转化为数组。Array.from
另外用
Array.from
处理带 Unicode 的字符是非常方便的,与str.split
方法不同,它依赖于字符串的可迭代特性。可以基于
Array.from
创建 UTF-16 扩展字符的slice
方法:另外解构也是类似原理:
The text was updated successfully, but these errors were encountered: