怎么做网站推广平台,wordpress 出名主题,国家工程招标网公告,专业网站设计流程图目录
一、由来及意义
二、具体实现流程
三、具有默认 Iterator 接口的数据结构
四、调用 Iterator 接口的场合
五、总结 一、由来及意义
Javascript中表示“集合”的数据结构#xff0c;主要是 Array、Object、Map、Set 这四种数据集合#xff0c;除此之外#xff0c;…目录
一、由来及意义
二、具体实现流程
三、具有默认 Iterator 接口的数据结构
四、调用 Iterator 接口的场合
五、总结 一、由来及意义
Javascript中表示“集合”的数据结构主要是 Array、Object、Map、Set 这四种数据集合除此之外它们相互之间还可以组合使用例如Array的成员是MapMap的成员是Object等。因此Javascript得需要一种统一的接口机制来处理所有不同的数据结构。
遍历器Iterator就是这样一种机制。它是一种接口可以为各种不同的数据结构提供一种访问机制访问接口任何数据结构部署Iterator接口就可以完成该数据结构成员的遍历操作Iterator 接口主要供for...of使用。
二、具体实现流程
Iterator的遍历过程
1. 创建一个指针对象指向数据解构的起始位置。
2. 第一次调用指针对象的next()方法指针指向数据结构的第一个成员。
3. 第二次调用指针对象的next()方法指针指向数据结构的第二个成员。
4. 不停调用指针对象的next()方法直到它指向数据结构结束的位置。类似于C语言中的链表
每一次调用next方法都会返回数据结构中被指针指向的成员的信息。该信息为一个对象其中包含value和done两个属性的对象{ value: something , done: false }value属性是当前成员的值done属性是一个布尔值表示遍历是否结束donefalse表示循环还没有结束donetrue 表示循环结束了。
模拟next方法返回值例子
下面代码定义了一个makeIterator函数它是一个遍历器生成函数作用就是返回一个遍历器对象。对数组[前端,收割,机]执行这个函数就会返回该数组的遍历器对象即指针对象goodjob。
function makeIterator(array){var index 0;//形成闭包保存指针指向位置index通过三元表达式返回当前信息对象。return {next: function(){return index array.length ? {value: array[index], done: false} : {value: undefined, done: true};}}
}var goodjob makeIterator([前端,收割,机])goodjob.next()// {value: 前端, done: false}
goodjob.next()// {value: 收割, done: false}
goodjob.next()// {value: 机, done: false}
goodjob.next()// {value: undefined, done: false}
由于 Iterator 只是把接口规格加到数据结构之上所以遍历器与它所遍历的那个数据结构实际上是分开的完全可以写出没有对应数据结构的遍历器对象或者说用遍历器对象模拟出数据结构。
另一种写法
function makeIterator(array) {var index 0; //形成闭包保存指针指向位置index通过if分支语句返回当前信息对象。return {next: function() {var result {value: undefined, done: true};if (index array.length) {result { value: array[index], done: false };}return result;}};
}// 使用示例
var iterable makeIterator([1, 2, 3]);
console.log(iterable.next().value); // 输出: 1
console.log(iterable.next().value); // 输出: 2
console.log(iterable.next().value); // 输出: 3
console.log(iterable.next().value); // undefined迭代结束
makeIterator 这个函数的目的是创建一个迭代器对象该对象可以遍历传入的数组。在JavaScript中一个迭代器对象需要实现next方法该方法在每次调用时返回数组的下一个元素。
在这个解决方案中makeIterator函数通过返回一个对象该对象具有一个next方法来创建一个迭代器。每次调用next方法时它都会返回数组中的下一个元素直至遍历完成此时done属性为truevalue属性为undefined。这是符合ES6中Iterable和Iterator协议的定义。
三、具有默认 Iterator 接口的数据结构
Iterator 接口的目的就是为所有数据结构提供了一种统一的访问机制当使用for...of循环遍历某种数据结构时该循环会自动去寻找 Iterator 接口。
因此当某种数据结构具有Iterator 接口即表示该数据结构是可遍历的iterable。
默认的 Iterator 接口部署在数据结构的Symbol.iterator属性或者说一个数据结构只要具有Symbol.iterator属性就可以认为是“可遍历的”iterable。Symbol.iterator属性本身是一个函数就是当前数据结构默认的遍历器生成函数。执行这个函数就会返回一个遍历器。至于属性名Symbol.iterator它是一个表达式返回Symbol对象的iterator属性这是一个预定义好的、类型为 Symbol 的特殊值所以要放在方括号内。
const object1 {[Symbol.iterator] : function () {return {next: function () {return {value: 1,done: true};}};}
};对象object1是可遍历的iterable因为具有Symbol.iterator属性。执行这个属性会返回一个遍历器对象。该对象的根本特征就是具有next方法。每次调用next方法都会返回一个代表当前成员的信息对象具有value和done两个属性。
凡是部署了Symbol.iterator属性的数据结构就称为部署了遍历器接口。调用这个接口就会返回一个遍历器对象。即不用任何处理就可以被for...of循环遍历。
原生具备 Iterator 接口的数据结构
ArrayMapSetStringTypedArrayNodeList 对象函数的 arguments 对象
数组的Symbol.iterator属性
let arr [前端, 收割, 机];
let iterator arr[Symbol.iterator](); //因为arr中属性Symbol.iterator返回的是一个函数//所以在[Symbol.iterator]后面添加(),使函数执行返回一个遍历器对象iterator.next() // { value: 前端, done: false }
iterator.next() // { value: 收割, done: false }
iterator.next() // { value: 机, done: false }
iterator.next() // { value: undefined, done: true }数组通过for of调用iterator接口生成的遍历器
const arr [前端, 收割, 机];for(let v of arr) {console.log(v); // 前端 收割 机
}Map通过for of调用iterator接口生成的遍历器
var handsome new Map();
handsome.set(GuangHui, 1handsome);
handsome.set(JiaHao, 2handsome);
handsome.set(NingDong, 666);
for (var [name, value] of handsome) {console.log(name : value);
}
// GuangHui: 1handsome
// JiaHao: 2handsome
// NingDong: 666Set 通过for of调用iterator接口生成的遍历器
var handsome new Set([GuangHui, JiaHao, NingDong]);
for (var boy of handsome) {console.log(boy);
}
// GuangHui
// JiaHao
// NingDong类数组对象通过for of调用iterator接口生成的遍历器
// 字符串
let str 前端收割机;for (let s of str) {console.log(s); // 前 端 收 割 机
}// DOM NodeList对象
let paras document.querySelectorAll(p);for (let p of paras) {p.classList.add(前端收割机);
}// arguments对象
function printArgs() {for (let x of arguments) {console.log(x);}
}
printArgs(前端, 收割机);
// 前端
// 收割机对于不具备Iterator接口的数据结构主要是对象都需要自己在Symbol.iterator属性上面部署这样才会被for...of循环遍历。
原因对象Object之所以没有默认部署 Iterator 接口是因为对象的哪个属性先遍历哪个属性后遍历是不确定的需要开发者手动指定。本质上遍历器是一种线性处理对于任何非线性的数据结构部署遍历器接口就等于部署一种线性转换。
下面是为对象添加 Iterator 接口的例子
let object2 {data: [ 前端, 收割,机],[Symbol.iterator]() {const self this; //将this指向赋予selflet index 0; //初始遍历下标return {next() {if (index self.data.length) {return {value: self.data[index], //每次调用遍历下标自增1done: false};} else {return { value: undefined, done: true }; //遍历结束返回该对象}}};}
};对于类似数组的对象存在数值键名和length属性部署 Iterator 接口有一个简便方法就是Symbol.iterator方法直接引用数组的 Iterator 接口。
let object3 {0: 前端,1: 收割,2: 机,length: 3,[Symbol.iterator]: Array.prototype[Symbol.iterator] //直接引用数组构造函数prototype中的 Symbol.iterator属性
};
for (let item of object3) {console.log(item); // 前端, 收割, 机
}注意普通对象部署特定数据结构的Symbol.iterator方法并无效果。例如普通对象部署数组的Symbol.iterator方法。
let object4 { //该对象不存在数值键名a: 前端,b: 收割,c: 机,length: 3,[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of object4) {console.log(item); // undefined, undefined, undefined
}如果Symbol.iterator方法对应的不是遍历器生成函数即会返回一个遍历器对象解释引擎将会报错。
var object5 {};obj[Symbol.iterator] () 前端收割机; //返回的是一个字符串[...object5] // TypeError: [] is not a function四、调用 Iterator 接口的场合
除了for...of循环某些场景会默认调用 Iterator 接口即Symbol.iterator方法 番外一文带你了解JavaScript中的for...of循环 注意事项 尽管 for...of 循环非常方便和实用但在使用时仍需要注意一些细节和注意事项以避免潜在的 bug 或错误。 首先需要注意的是for...of 循环只能用于遍历实现了迭代器协议的对象。如果我们尝试使用 for...of 循环遍历一个不支持迭代器协议的对象会导致 TypeError 错误。 其次需要注意的是for...of 循环只能访问迭代器的值而不能访问迭代器的索引或键。如果我们需要访问迭代器的索引或键可以考虑使用其他循环结构如 for 循环或 forEach 方法。 最后需要注意的是for...of 循环中的迭代变量是一个常量其值在每次迭代中都会被重新赋值。因此我们不能在循环中修改迭代变量的值否则会导致错误。 解构赋值
let set new Set().add(前端).add(收割).add(机); //Set通过add方法进行链式添加值let [one,two] set;
// x前端; y收割let [one, ...two] set;
// one前端; two[收割,机];扩展运算符
// 例一
var str 前端收割机;
[...str] // [前,端,收,割,机]// 例二
let arr [是, 靓];
[我, ...arr, 仔]
// [我, 是, 靓, 仔]扩展运算符内部就调用 Iterator 接口这提供了一种简便机制可以将任何部署了 Iterator 接口的数据结构通过扩展运算符转为数组。
yield*
yield*后面跟的是一个可遍历的结构它会调用该结构的遍历器接口。
let generator function* () {yield 我;yield* [是,靓,仔];yield 啊;
};var iterator generator();iterator.next() // { value: 我, done: false }
iterator.next() // { value: 是, done: false }
iterator.next() // { value: 靓, done: false }
iterator.next() // { value: 仔, done: false }
iterator.next() // { value: 啊, done: false }
iterator.next() // { value: undefined, done: true }Array.from()
往Array.from()函数以类数组形式输入值Array.from()函数调用Iterator接口将输入的类数组转化成数组
let arrayLike {0: 前端, 1: 收割,2: 机,3: [GuangHui,JiaHao,NingDong],length: 4
}
let arr Array.from(arrayLike)
console.log(arr) // [前端,收割,机,[GuangHui,JiaHao,NingDong]]Map(), Set(), WeakMap(), WeakSet()
往Map构造函数以数组形式输入键值对新建Map对象时Map构造函数调用Iterator接口遍历存入键值对
var goodJob new Map([[前端,1],[收割机,2]]) Promise.all()
往Promise.all()函数以Promise数组形式输入值Promise.all()函数调用Iterator接口将promise请求遍历执行。
const p Promise.all([p1, p2, p3]);Promise.all()方法接受一个数组作为参数p1、p2、p3都是 Promise 实例如果不是就会先调用Promise.resolve方法将参数转为 Promise 实例再进一步处理。另外Promise.all()方法的参数可以不是数组但必须具有 Iterator 接口且返回的每个成员都是 Promise 实例。
Promise.race()
往Promise.race()函数以Promise数组形式输入值Promise.race()函数调用Iterator接口将promise请求遍历执行。
const p Promise.race([p1, p2, p3]);Promise.race()方法接受一个数组作为参数p1、p2、p3都是 Promise 实例如果不是就会先调用Promise.resolve方法将参数转为 Promise 实例再进一步处理。另外Promise.race()方法的参数可以不是数组但必须具有 Iterator 接口且返回的每个成员都是 Promise 实例。
● 补充Generator 函数与 Iterator 接口的关系
对象的Symbol.iterator方法等于该对象的遍历器生成函数调用该函数会返回该对象的一个遍历器对象。由于 Generator 函数就是遍历器生成函数因此可以把 Generator 赋值给对象的Symbol.iterator属性从而使得该对象具有 Iterator 接口。
五、总结
▲遍历器Iterator可以为各种不同的数据结构提供一种访问机制访问接口任何数据结构部署Iterator接口就可以完成该数据解构成员的遍历操作Iterator 接口主要供for...of使用。
▲Iterator的遍历过程创建一个指针对象指向数据解构的起始位置。不停调用指针对象的next()方法指针往后移动直到它指向数据结构结束的位置。每一次调用next方法都会返回数据结构中被指针指向的成员的信息{ value: something , done: false }。
▲ArrayMapSetStringTypedArrayNodeList 对象函数的 arguments 对象为原生具备 Iterator 接口的数据结构。
▲调用 Iterator 接口的场合for...of循环、解构赋值、扩展运算符、yield*、Array.from()、Map()、Set()、 WeakMap()、 WeakSet()、Promise.all()、Promise.race()。
✔ 参考资料
JavaScript中Iterator迭代器接口和循环_脚本之家 | Iterator(遍历器)接口概念以及用法
JavaScript中Iterator迭代器接口和循环 - Python技术站 | JS– Iterator接口 | JS_ES6 - Iterator