一.迭代器
1.迭代器是帶有特殊接口的對象
,返回一個next
方法佣谐,該方法中同時又value
和done
屬性,當(dāng)再沒有值可以迭代時,value
為undefined
方妖,done
為true
台谍,否則value
為當(dāng)前值,done
為false
2.根據(jù)上面的描述實(shí)現(xiàn)一個迭代器,如下:
let iterator = {
i: 0,
items: [2, 4, 6],
next() {
let value, done;
done = (this.i === this.items.length);
value = done ? undefined : this.items[this.i++];
return {
value: value,
done: done
}
}
};
console.log(iterator.next()); //{value: 2, done: false}
console.log(iterator.next()); //{value: 4, done: false}
console.log(iterator.next()); //{value: 6, done: false}
console.log(iterator.next()); //{value: undefined, done: true}
二.生成器
1.生成器是返回迭代器的函數(shù)趁蕊,如下:
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
let iterator = createIterator();
console.log(iterator.next()); //{value: 1, done: false}
console.log(iterator.next()); //{value: 2, done: false}
console.log(iterator.next()); //{value: 3, done: false}
console.log(iterator.next()); //{value: undefined, done: true}
2.生成器有幾點(diǎn)要注意的:
- 當(dāng)執(zhí)行流遇到y(tǒng)ield語句時,該生成器就停止運(yùn)轉(zhuǎn)了仔役,直到迭代器再次調(diào)用next
- 可以再for循環(huán)中使用yield
- yield只能用在生成器的內(nèi)部掷伙,即使是生成器內(nèi)部的函數(shù)也不行,即:yield無法跨越函數(shù)邊界
- 無法使用箭頭函數(shù)創(chuàng)建生成器
- 生成器可以存在于對象的屬性中
三.for-of循環(huán)
1.可迭代類型:指那些包含Symbol.iterator
屬性的對象又兵,該屬性定義了返回迭代器的函數(shù)(如:數(shù)組任柜,set,map等)
2.for-of循環(huán)可以循環(huán)可迭代類型沛厨,for-of循環(huán)會在可迭代類型每次執(zhí)行后調(diào)用next()并將結(jié)果存儲在變量中宙地,循環(huán)會持續(xù)進(jìn)行,直到結(jié)果對象的done屬性為true
3.for-of循環(huán)會調(diào)用數(shù)組的Symbol.iterator
屬性來獲取迭代器(該方法由幕后的js引擎調(diào)用)逆皮,并將調(diào)用iterator.next()宅粥,并將該結(jié)果對象的value屬性的值賦給num,直到done為true电谣,循環(huán)會退出秽梅,num不會被賦給undefined,代碼如下:
let values = [1, 2, 3];
for (let item of values) {
console.log(item); //1 2 3
}
4.對于非可迭代對象剿牺,如null
和undefined
企垦,使用for-of循環(huán)會拋出錯誤
5.可以在for-of循環(huán)中使用解構(gòu)
let map = new Map();
map.set('name', 'sxt');
map.set('age', 2);
for(let [key, value] of map) {
console.log(key + " = " + value);
}
//輸出:
//name = sxt
//age = 2
6.for-of循環(huán)可以用于循環(huán)NodeList
四.Symbol.iterator
1.可以用Symbol.iterator
屬性來訪問對象默認(rèn)的迭代器,如:
let arr = [6, 7, 8];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next()); //{value: 6, done: false}
console.log(iterator.next()); //{value: 7, done: false}
console.log(iterator.next()); //{value: 8, done: false}
console.log(iterator.next()); //{value: undefined, done: true}
2.判斷一個對象是否可以迭代晒来,可以通過判斷Symbol.iterator
屬性是否是一個函數(shù)來實(shí)現(xiàn)钞诡,如:
function isIterator(obj) {
return typeof obj[Symbol.iterator] === 'function';
}
let arr = [1, 3, 4];
let num = 1;
console.log(isIterator(arr)); //true
console.log(isIterator(num)); //false
3.創(chuàng)建可迭代類型: 我們自己定義的對象默認(rèn)是不可迭代類型,但是我們可以通過設(shè)置Symbol.iterator
屬性來使這個對象可以迭代湃崩。因?yàn)榍懊娴?點(diǎn)有講到荧降,判斷一個對象是否可以迭代,其實(shí)是通過Symbol.iterator
屬性來確定的竹习,由此可以創(chuàng)建下面的對象
let obj = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
for (let item of obj) {
console.log(item); //1 2 3
}
五.內(nèi)置迭代器
1.我們平常迭代數(shù)組誊抛,set和map時,能拿到迭代的值整陌,是因?yàn)檫@些集合中有內(nèi)置的迭代器拗窃,如
let arr = [1, 3, 5];
let set = new Set();
set.add('time');
set.add('user');
set.add('family');
let map = new Map();
map.set('name', 'sxt');
map.set('age', 12);
map.set('sister', 'andy');
for(let item of arr) {
console.log(item); // 1 3 5
}
for(let item of set) {
console.log(item); //time user family
}
for(let item of map) {
console.log(item); //["name", "sxt"] ["age", 12] ["sister", "andy"]
}
2.內(nèi)置迭代器分為三種
- entries()
- keys()
- values()
3.數(shù)組的entries返回的是[索引,值]
泌辫,set的entries是[值随夸,值]
,因?yàn)閟et的鍵值是一樣的震放,map的entries是[鍵名宾毒,鍵值]
,如:
let arr = [1, 3, 5];
let set = new Set();
set.add('time');
set.add('user');
set.add('family');
let map = new Map();
map.set('name', 'sxt');
map.set('age', 12);
map.set('sister', 'andy');
for(let item of arr.entries()) {
console.log(item); // [0, 1] [1, 3] [2, 5]
}
for(let item of set.entries()) {
console.log(item); //["time", "time"] ["user", "user"] ["family", "family"]
}
for(let item of map.entries()) {
console.log(item); //["name", "sxt"] ["age", 12] ["sister", "andy"]
}
4.數(shù)組的keys返回的索引殿遂,set的keys返回的還是值诈铛,map的keys返回的是值
5.數(shù)組乙各,set,map的values返回的都是值
六.向迭代器中傳遞參數(shù)
1.我們可以向迭代器中傳遞參數(shù)
function *createIterator() {
let first = yield 1;
let second = yield first + 2;
yield second + 3;
}
let iterator = createIterator();
console.log(iterator.next()); //{value: 1, done: false}
console.log(iterator.next(4)); //{value: 6, done: false}
console.log(iterator.next(5)); //{value: 8, done: false}
console.log(iterator.next()); //{value: undefined, done: true}
- 這里的難點(diǎn)是理解右側(cè)的代碼會和左邊的中斷
- 首次調(diào)用next的時候幢竹,不管傳入什么參數(shù)都會被忽略耳峦,因?yàn)閭魅氲膮?shù)會作為yield語句的返回值,而第一次只是yield 1焕毫,而沒有變量
七.包含return語句的生成器
function *createIterator() {
yield 1;
return 133;
yield 2;
yield 3;
}
let iterator = createIterator();
console.log(iterator.next()); //{value: 1, done: false}
console.log(iterator.next(4)); //{value: 133, done: true}
console.log(iterator.next(5)); //{value: undefined, done: true}
console.log(iterator.next()); //{value: undefined, done: true}
- return會讓它提前執(zhí)行完畢并針對next的調(diào)用返回一個值
八.生成器代理
1.即蹲坷,在一個生成器中調(diào)用另外的生成器,有時候邑飒,這樣的操作會更加的實(shí)用
function *create1() {
yield 1;
yield 2;
yield 3;
}
function *create() {
yield *create1();
yield true;
}
let iterator = create();
console.log(iterator.next()); //{value: 1, done: false}
console.log(iterator.next()); //{value: 2, done: false}
console.log(iterator.next()); //{value: 3, done: false}
console.log(iterator.next()); //{value: true, done: false}
console.log(iterator.next()); //{value: undefined, done: true}