作者:dendoink
連接:https://juejin.im/post/6844903762931236878
來源:掘金
const testArr = ['foo', 'bar'];
console.log(testArr);
我們會發現數組( 或是類數組對象比方說Map、arguments、Sets )的__ proto __ 裡面都會有一個Symbol.iterator方法!
const testArr = ['foo', 'bar'];
// console.log(testArr);
let iterator = testArr[Symbol.iterator]();
// 打印看看這個iterator方法看長怎樣
console.dir(iterator);
const testArr = ['foo', 'bar'];
// console.log(testArr);
let iterator = testArr[Symbol.iterator]();
// 打印看看這個iterator方法看長怎樣
// console.dir(iterator);
// 打印出使用next方法後的回傳值
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
其實 for of 循環就是基於這個完成遍歷的
- 對應下標的值 (回傳的value值)
- 遍歷結束的標誌 (回傳的done是否為true)
iterator
(迭代器) & The iterator protocol
(迭代協議)先來看一下迭代協議在MDN上面的定義
簡單來說就是
JavaScript 允許對象自行定義iteration完成迭代行為
比方說剛剛那個數組的是透過next()方法完成的,這也就是為何對象並不能用for of 進行迭代,因為它本身並沒有定義iterator
let foo = {
bar: 'bar',
haha: 'haha'
}
console.dir(foo);
雖然標準並沒有為我們設置itearator,但我們可以自己設置
Object.prototype[Symbol.iterator] = function*() {
for (const [key, value] of Object.entries(this)) {
yield { key, value };
}
};
for (const { key, value } of { a: 1, b: 2, c: 3 }) {
console.log(key, value);
}
這個奇怪的格式,就是等等要講的generator
funciotn* () {...}
直接看例子
// 下面就是generator 函數
function* foo() {
yield 1
yield 2
yield 3
}
console.dir(foo);
居然有我們熟悉的next方法,來實際操作一下foo函數看會發生甚麼
function* foo() {
yield 1
yield 2
yield 3
}
// console.dir(foo);
let instance = foo()
console.log(instance.next());
console.log(instance.next());
console.log(instance.next());
console.log(instance.next());
哇看到這應該滿明顯了吧
當我們generator函數可以創造出iterator,而yield則是中斷代碼執行,可以透過next()方法繼續執行下去
來看一個奇怪的例子
function* gen() {
yield 1
yield* gen2()
return
yield 2
}
function* gen2() {
yield 4
yield 5
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
- 可以發現yield也可以放上generator函數,並會接續執行下去
- retrun 後面的yield不會執行
終止代碼的特性可以幫我們處理異步
直接看例子
B函數的執行參數是從A傳來,因此需要等A執行完才可以執行B
function* effect() {
const { param } = yield A();
const { result } = yield B(param);
console.table(result);
}
const iterator = effect()
iterator.next()
iterator.next()