文章目錄
-
-
-
- Iterator 的概念
- 預設的 Iterator接口
- 調用 Iterator 接口的場合
- 字元串的 Iterator 接口
- Iterator 接口與 Generator 函數
- for...of 循環
-
-
Iterator 的概念
-
就是這樣一種機制。它是一種接口,為各種不同的資料結構提供統一的通路機制。任何資料結構隻要部署 Iterator 接口,就可以完成周遊器(Iterator
(即依次處理該資料結構的所有成員)。周遊操作
- Iterator 的作用有三個
- 一、 是為各種資料結構,提供一個統一的、簡便的通路接口;
- 二 、是使得資料結構的成員能夠按某種次序排列;
- 三 、是 ES6 創造了一種新的周遊指令
循環,Iterator 接口主要供for…of消費。for...of
-
傳回值next方法
function upper(array){
let index = 0
return{
next(){
return index < array.length ? {value:array[index++], done:false}: {value:undefined, done:true}
// return index < array.length ? {value:array[index++]}: {done:true}
// 簡便的寫法(下面會有介紹原因)
}
}
}
let maker = new upper([1, 2, 3])
console.log( maker.next()) // value: 1 done: false
console.log( maker.next()) // value: 2 done: false
console.log( maker.next()) // value: 3 done: false
console.log( maker.next()) // value: undefined done: true
console.log( maker.next()) // value: undefined done: true
//每一次調用next方法,都會傳回資料結構的目前成員的資訊。具體來說,就是傳回
//一個包含`value`和`done`兩個屬性的對象。其中,`value屬性是目前成員的值`,
//`done屬性是一個布爾值,表示周遊是否結束`。
- 指針對象的
,用來移動指針。開始時,指針指向數組的next方法
。然後,每次調用next方法,指針就會指向數組的下一個成員。第一次調用,指向 1 ;第二次調用,指向 2 。開始位置
-
方法傳回一個對象,表示目前資料成員的資訊。這個對象具有next
和value
兩個屬性,value屬性傳回目前位置的成員,done屬性是一個布爾值,表示周遊是否結束,即是否還有必要再一次調用next方法。done
- 對于周遊器對象來說,
和done: false
屬性都是可以省略的,是以我們在代碼編寫時可以忽略這兩個屬性的設定value: undefined
預設的 Iterator接口
- ES6 規定,預設的
部署在資料結構的Iterator 接口
屬性,或者說,一個資料結構隻要具有Symbol.iterator
屬性,就可以認為是“可周遊的”(iterable)。Symbol.iterator
-
屬性本身是一個函數,就是目前資料結構預設的周遊器生成函數。執行這個函數,就會傳回一個周遊器。至于屬性名Symbol.iterator
,它是一個Symbol.iterator
,傳回Symbol對象的iterator屬性,表達式
這是一個預定義好的、類型為 Symbol 的特殊值,是以要放在方括号内。
// 手動部署周遊器生成方法
// 為對象添加 Iterator 接口
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
obj[Symbol.iterator]().next() // {value: 1, done:true}
- 對于
的對象(類似數組
),部署存在數值鍵名和length屬性
接口,有一個簡便方法,就是Iterator
r方法直接引用Symbol.iterato
的 Iterator 接口。數組
// NodeList 為類數組對象
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
// 或者
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
- 但是對于非類數組對象,上面的方法是無效的。
let iterable = {
a: 'a',
b: 'b',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let value of iterable) {
console.log(value); // undefined, undefined
}
調用 Iterator 接口的場合
- (1)解構指派
- 對數組和 Set 結構進行解構指派時,會預設調用
方法。Symbol.iterator
let newarrray = [1, 2, 3, 4]
let [start, ...end] = newarrray
let newset = new Set([1, 2, 2, 3])
let [start1, ...end1] = newset
// 上面的兩種方法都會預設調用 Symbol.iterator方法,即周遊 newarray 和 newset
- (2)擴充運算符
- 擴充運算符(…)也會調用預設的 Iterator 接口。
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
- (3)其他場合
- 由于數組的周遊會調用周遊器接口,是以任何接受數組作為參數的場合,其實都調用了周遊器接口。下面是一些例子。
-
for...of
Array.from()
,Map()
,Set()
,WeakMap()
WeakSet()
Promise.all()
上面這些的參數都可以接收數組作為參數。Promise.race()
字元串的 Iterator 接口
- 下面是一種比較特殊的情況
var str = new String("hi");
str[Symbol.iterator] = function() {
return {
next: function() {
if (this._first) {
this._first = false;
return { value: "bye", done: false };
} else {
return { done: true };
}
},
_first: true
};
};
[...str] // ["bye"]
str // "hi"
// 由于擴充運算符(...)使用時會預設調用 iterator 接口,而 iterator 部署
// 在 Symbol.iterator 上,是以此時我們會執行 Symbol.iterator 内的方法
// 在手動更改了他的屬性之後,可以看到有明顯不同的效果
Iterator 接口與 Generator 函數
let myIterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
}
}
[...myIterable] // [1, 2, 3]
// Generator函數會在下一篇部落格詳細的介紹
for…of 循環
- 一個資料結構隻要部署了
屬性,就被視為具有 iterator 接口,就可以用Symbol.iterator
循環周遊它的成員。也就是說,for...of
循環内部調用的是資料結構的for...of
方法。Symbol.iterator
- for…of循環可以使用的範圍包括
、數組
、某些Set 和 Map 結構
(比如arguments對象、DOM NodeList 對象)、類似數組的對象
,以及Generator 對象
。字元串
- 數組
let newerarrray = [1, 2, 3, 4]
for(let value of newerarrray){
console.log(value)
// 1 2 3 4
}
--------------------------------------------------------------------
//for...of循環調用周遊器接口,數組的周遊器接口隻傳回具有數字索引的屬性
let newerarrray = [1, 2, 3, 4]
newerarrray.foo = 'hello'
for(let value of newerarrray){
console.log(value)
// [1, 2, 3, 4]
}
// 此時的數組結構 [1, 2, 3, 4, foo:'hello'],由于 foo不是數字索引,是以不傳回'hello'
--------------------------------------------------------------------
//for...of循環讀取鍵值。如果要通過for...of循環,擷取數組的索引,可以借助
//數組執行個體的entries方法和keys方法
newerarrray = ['a', 'b', 'c']
for(let value of newerarrray.entries()){
console.log(value)
// [0,'a'], [1, 'b'], [2, 'c']
// 輸出同時具有索引和值得數組
}
for(let value of newerarrray.keys()){
console.log(value)
// 0 1 2
// 輸出每個值得索引
}
- Set 和 Map 結構
// Set 結構周遊時,傳回的是一個值
let newset = new Set([1, 2, 2, 3])
for (let value of newset){
console.log(value)
// 1, 2, 3
}
// Map 結構周遊時,傳回的是一個數組,該數組的兩個成員分别為目前 Map 成員
// 的鍵名和鍵值。
let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
console.log(pair);
}
// ['a', 1]
// ['b', 2]
- 類似數組的對象
// 字元串
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");
// 為不同的 p标簽 添加新的類名,如已經存在,取消添加
}
// arguments對象
function printArgs() {
for (let x of arguments) {
console.log(x);
}
}
printArgs('a', 'b');
// 'a'
// 'b'
-------------------------------------------------------------------
//當遇到類數組對象不能夠用 for...of周遊時,我們可以将其轉化為數組
```javascript
let arrayLike = { length: 2, 0: 'a', 1: 'b' };
for (let x of Array.from(arrayLike)) {
......
}
- 對象
//對于普通的對象,for...of結構不能直接使用,會報錯,必須部署了 Iterator 接
//口後才能使用
let stu = {
name : 'Jack',
age : 18
}
for (let value of stu){} // Error
// 部署Iterator的方法 => 添加 Symbol.iterator屬性