前言
變量的解構賦值是前端開發中經常用到的一個技巧,比如:
// 對象解構
const obj = { a: 1, b: 2 };
const { a, b } = obj;
console.log(a, b)數組解構
const arr = [1, 2, 3];
const [a, b] = arr;
console.log(a, b)
工作中我們最經常用的就是類似上面的對象和數組解構,好多同學就不禁問了,這個不是很簡單嗎。
那好,我們再來看一個:
// 不改動下面代碼,如何使等式成立
const [a, b] = { a: 1, b: 2 };
console.log(a, b)
你覺得這個打印出來什么呢?
直接報錯:{(intermediate value)(intermediate value)} is not iterable
翻譯過來就是值是不可迭代的,這是為什么呢?因為右邊的值是不可迭代對象
可迭代對象
什么是可迭代對象?
可迭代對象就是滿足 可迭代協議 的對象。
可迭代協議 中必須有這么一個屬性:Symbol.iterator,一個無參數的函數,其返回值為一個符合 可迭代協議 的對象,即迭代器。
數組解構
數組可以解構,因為數組是一個可迭代對象。
const arr = [1, 2, 3];
const iter = arr[Symbol.iterator]();
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
我們看一下打印結果:
value
代表的是這次迭代的值,done
代表迭代是否完成。
這就是 可迭代協議 的規則。
數組解構就相當于下面這種寫法:
const arr = [1, 2, 3];
// const [a,b] = arr;
const iter = arr[Symbol.iterator]();
const a = iter.next().value;
const b = iter.next().value;
console.log(a, b)
對象解構
那么問題來了,對象身上沒有 Symbol.iterator,為什么還能解構?
因為對象的解構過程是這樣的:創建對象 -> 枚舉屬性(OwnPropertyKeys) -> 復制屬性
,跟迭代器沒關系。
對象解構就相當于下面這種寫法:
const obj = { a: 1, b: 2 };
// const { a, b } = obj;
const a = obj.a;
const b = obj.b;
問題解決
我們捋清楚問題的起因,問題就好解決了,我們只需要在對象的原型上也添加一個 Symbol.iterator 屬性就可以了:
Object.prototype[Symbol.iterator] = function () {return Object.values(this)[Symbol.iterator]();
}
const [a, b] = { a: 1, b: 2 };
console.log(a, b)
這樣就能使等式成立,而且如果你的 ES6
功底足夠的扎實,還知道什么叫 生成器Generator,那你還可以這樣寫:
Object.prototype[Symbol.iterator] = function* () {yield* Object.values(this);
}
const [a, b] = { a: 1, b: 2 };
console.log(a, b)
最終效果是一樣的。
如果你對這些還不是很熟悉,建議你看一下 ES6
的文檔:ECMAScript 6 入門教程