面試官:如何讓 var [a, b] = {a: 1, b: 2} 解構(gòu)賦值成功?
最近看到了一個(gè)面試題非常有意思,講得是:如何讓 var [a, b] = {a: 1, b: 2} 解構(gòu)賦值成功?。
我們知道在 js 中 []代表數(shù)組,{}代表對(duì)象 。但是在這個(gè)代碼中:
- 解構(gòu)賦值語法的左側(cè)是一個(gè)數(shù)組
- 右側(cè)則應(yīng)該是一個(gè)具有迭代器接口的對(duì)象(如數(shù)組、Map、Set等)。
因此,將對(duì)象 {a: 1, b: 2} 解構(gòu)賦值給 [a, b] 會(huì)導(dǎo)致語法錯(cuò)誤,那么怎么解決呢?我們來看一下!
思路
錯(cuò)誤思路
既然將一個(gè)對(duì)象解構(gòu)賦值給數(shù)組,是一個(gè)語法錯(cuò)誤,那我們直接把這個(gè)解構(gòu)語法變?yōu)閷?duì)象的解構(gòu)賦值語法不就好了。直接改成var { a, b } = { a: 1, b: 2 }; 如果這樣做的話,哈哈哈哈哈哈,恭喜你面試結(jié)束了。
所以我們得好好想清楚,這可是一個(gè)字節(jié)的面試題,它的考點(diǎn)可不是這么顯而易見的。
正確解題思路
我們首先來看看報(bào)錯(cuò)是什么樣的:
var [a, b] = {a: 1, b: 2}
TypeError: {(intermediate value)(intermediate value)} is not iterable
這個(gè)錯(cuò)誤是個(gè)類型錯(cuò)誤,并且是對(duì)象有問題,因?yàn)閷?duì)象是一個(gè)不具備迭代器屬性的數(shù)據(jù)結(jié)構(gòu)。所以我們可以知道,這個(gè)面試題就是考驗(yàn)我們對(duì)于迭代器屬性的認(rèn)識(shí),我們?cè)賮韨€(gè)場(chǎng)景加深下理解。
let arr = [1, 2, 3]
let obj = {
a: 1,
b: 2,
c: 3
}
for(let item of arr){
console.log(item)
}
for(let item of obj){
console.log(item)
}
我們知道for of 只能遍歷具有迭代器屬性的,在遍歷數(shù)組的時(shí)候會(huì)打印出1 2 3,遍歷對(duì)象時(shí)會(huì)報(bào)這樣的一個(gè)錯(cuò)誤TypeError: obj is not iterable,那么數(shù)組上的迭代器屬性究竟是什么樣的呢,我們來看一看。
我們可以在最下面發(fā)現(xiàn),數(shù)組原型上有Symbol.iterator這樣一個(gè)屬性,這個(gè)屬性顯然是從Array身上繼承到的,并且這個(gè)屬性的值是一個(gè)函數(shù)體,如果我們調(diào)用一下這個(gè)函數(shù)體會(huì)怎么樣?我們打印來看看
console.log(arr.__proto__[Symbol.iterator]());
// Object [Array Iterator] {}
最重要的點(diǎn)來了
它返回的是一個(gè)對(duì)象類型,并且是一個(gè)迭代器對(duì)象?。?!所以一個(gè)可迭代對(duì)象的基本結(jié)構(gòu)是這樣的:
interable
{
[Symbol.iterator]: function () {
return 迭代器 (可通過next()就能讀取到值)
}
}
我們可以得出只要一個(gè)數(shù)據(jù)結(jié)構(gòu)身上,具有[Symbol.iterator]這樣一個(gè)屬性,且值是一個(gè)函數(shù)體,可以返回一個(gè)迭代器的話,我們就稱這個(gè)數(shù)據(jù)結(jié)構(gòu)是可迭代的。
這時(shí)候我們回到面試題之中,面試官要我們讓 var [a, b] = {a: 1, b: 2} 這個(gè)等式成立,那么有了上面的鋪墊,我們可以知道,我們接下來的操作就是:人為的為對(duì)象打造一個(gè)迭代器出來,也就是讓對(duì)象的隱式原型可以繼承到迭代器屬性,我們可以先這樣做:
Object.prototype[Symbol.iterator] = function(){
}
var [a, b] = {a: 1, b: 2}
console.log(a,b);
這樣的話,報(bào)錯(cuò)就改變了,變成:
TypeError: Result of the Symbol.iterator method is not an object
接下來,我們知道var [a, b] = [1, 2]這是肯定沒有問題的,所以我們可以將對(duì)象身上的迭代器,打造成和數(shù)組身上的迭代器(arr[Symbol.iterator])一樣,代碼如下:
Object.prototype[Symbol.iterator] = function(){
// 使用 Object.values(this) 方法獲取對(duì)象的所有值,并返回這些值的迭代器對(duì)象
return Object.values(this)[Symbol.iterator]()
}
這段代碼是將 Object.prototype 上的 [Symbol.iterator] 方法重新定義為一個(gè)新的函數(shù)。新的函數(shù)通過調(diào)用 Object.values(this) 方法獲取對(duì)象的所有值,并返回這些值的迭代器對(duì)象。
通過這個(gè)代碼,我們可以使得任何 JavaScript 對(duì)象都具有了迭代能力。例如,對(duì)于一個(gè)對(duì)象 obj,我們可以直接使用 for...of 循環(huán)或者 ... 操作符來遍歷它的所有值。