- 一是为各种数据结构,提供一个统一的、简便的访问接口
- 二是使得数据结构的成员能够按某种次序排列
- Iterator 接口主要供
for...of
消费目前知道四种数据集合(Array、Object、Map、Set)
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的
next
方法,可以将指针指向数据结构的第一个成员。(3)第二次调用指针对象的
next
方法,指针就指向数据结构的第二个成员。(4)不断调用指针对象的
next
方法,直到它指向数据结构的结束位置。返回value(成员值)和done(布尔值:表示遍历是否结束)
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};//两个属性都是可以省略
}
};
}
没有对应的数据结构,遍历器对象会自己描述了一个数据结构出来
var it = idMaker();//这里没有数据结构
it.next().value // 0
it.next().value // 1
it.next().value // 2
// ...
function idMaker() {
var index = 0;
return {
next: function() {
return {value: index++, done: false};
}
};
}
ES6 规定,一个数据结构只要具有
Symbol.iterator
属性,就可以认为是“可遍历的”
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
原生具备 Iterator 接口的数据结构如下 :
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
个数据结构只要部署了
Symbol.iterator
属性,就被视为具有 iterator 接口,就可以用for...of
循环遍历它的成员。也就是说,for...of
循环内部调用的是数据结构的Symbol.iterator
方法替代forEach方法
arguments
对象、DOM NodeList 对象)、 Generator 对象,以及字符串for...in
循环读取键名(下标)for...of
循环读取键值entries
方法和keys
方法const arr = ['red', 'green', 'blue'];
for(let v of arr) {
console.log(v); // red green blue
}
const obj = {};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);
for(let v of obj) {
console.log(v); // red green blue
}
ar engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
console.log(e);
}
// Gecko
// Trident
// Webkit
var es6 = new Map();
es6.set("edition", 6);
es6.set("committee", "TC39");
es6.set("standard", "ECMA-262");
for (var [name, value] of es6) {
console.log(name + ": " + value);
}
// edition: 6
// committee: TC39
// standard: ECMA-262
// 字符串
let str = "hello";
for (let s of str) {
console.log(s); // h e l l o
}
// DOM NodeList对象
let paras = document.querySelectorAll("p");
for (let p of paras) {
p.classList.add("test");
}
// arguments对象
function printArgs() {
for (let x of arguments) {
console.log(x);
}
}
printArgs('a', 'b');
// 'a'
// 'b'
let es6 = {
edition: 6,
committee: "TC39",
standard: "ECMA-262"
};
for (let e in es6) {
console.log(e);
}
// edition
// committee
// standard
for (let e of es6) {
console.log(e);
}
// TypeError: es6[Symbol.iterator] is not a function
//--------------------------------------------
解决方法:将对象转为数组
for (var key of Object.keys(someObject)) {
console.log(key + ': ' + someObject[key]);
}
Generator 函数是一个状态机,封装了多个内部状态;
执行 Generator 函数会返回一个遍历器对象
Generator 函数是一个普通函数,
function
关键字与函数名之间有一个星号- 函数体内部使用
yield
表达式function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hw = helloWorldGenerator();
Generator函数就算使用函数调用方式不会直接执行,需要next方法:每次调用时候调用一次方法
yield
表达式是暂停执行的标记,而next
方法可以恢复执行
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
- 遇到
yield
表达式,就暂停执行后面的操作- 下一次调用
next
方法时,再继续往下执行- 如果没有再遇到新的
yield
表达式,就一直运行到函数结束,直到return
语句为止- 如果该函数没有
return
语句,则返回的对象的value
属性值为undefined
const obj = {
name: "haha",
age: 18,
};
obj[Symbol.iterator] = objectEntries; //生成器
function* objectEntries(obj) {
// 获取对象那个的所有的key
// 保存到数组中
const propKeys = Object.keys(obj); //获取对象中的所有key
for (const propkey of propKeys) {
// 生成器键值对
yield [propkey, obj[propkey]];
}
}
console.log(obj);
//生成器生成之后
for (let [key, value] of objectEntries(obj)) {
console.log(`${key},${value} `);
}