有迭代器接口的數(shù)據(jù)的解構(gòu)賦值
基本用法
let [a, b, c] = [1, 2, 3];
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
凡是右邊數(shù)據(jù)是有迭代器接口的數(shù)據(jù),就都可以解構(gòu)拱她,常見的有迭代器接口的數(shù)據(jù)就是數(shù)組二驰。
如果右邊數(shù)據(jù)不是具有迭代器接口的數(shù)據(jù),那就不能解構(gòu)秉沼,會(huì)報(bào)錯(cuò)桶雀。
解構(gòu)的順序是從左到右,上面例子就是先解構(gòu)第一個(gè)元素氧猬,賦值給第一個(gè)變量背犯,然后向右進(jìn)行坏瘩。
復(fù)雜用法
解構(gòu)賦值本質(zhì)是模式匹配盅抚,只要等號(hào)兩邊的模式相同,左邊的變量就會(huì)被賦予對(duì)應(yīng)的值倔矾,如果不匹配妄均,則只有匹配的幾個(gè)變量會(huì)被賦值柱锹,其他變量默認(rèn)為undefined。
let [a, [[b], c]] = [1, [[2], 3]];
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
let [,,c] = [1,2,3];
console.log(c); // 3
let [,c,] = [1,2,3];
console.log(c); // 2
輪不到賦值的變量丰包,值為undefined:
let [a,b] = [1];
console.log(b);
剩余符號(hào)的用法:
剩余符號(hào)就是...
禁熏,也就是三個(gè)點(diǎn),表示剩下的我全包了邑彪。只允許用在最后一個(gè)變量的身前瞧毙。
let [a, ...b] = [1, 2, 3, 4, 5];
console.log(b); // [2, 3, 4, 5]
let [a, ...b, c] = [1, 2, 3, 4, 5];
console.log(b); // Uncaught SyntaxError: Rest element must be last element
如果剩余變量輪不到賦值,默認(rèn)值不是undefined寄症,而是空數(shù)組:
let [a,b,...c] = [1,2];
console.log(c); // []
模式差別會(huì)導(dǎo)致報(bào)錯(cuò)
所謂模式宙彪,可以簡(jiǎn)單理解為,數(shù)組符號(hào)[]和對(duì)象符號(hào){}組成的架構(gòu)有巧,必須是左右匹配的释漆,元素可以多一點(diǎn)少一點(diǎn)沒關(guān)系,頂多是undefined篮迎,但是模式不匹配男图,會(huì)直接報(bào)錯(cuò)。
看下面栗子甜橱,盡管給a賦值1看起來是天經(jīng)地義的逊笆,但是模式不同,所以js報(bào)錯(cuò)渗鬼±缆叮可見,模式匹配是必須的:
let [a, [b,c]] = [1,2,3];
a; // Uncaught TypeError: undefined is not a function
let [a, [b,c]] = [1,[]];
a; // 1
b; // undefined 因?yàn)槠ヅ洳簧现禌]關(guān)系譬胎,至少模式?jīng)]錯(cuò)差牛,所以不會(huì)報(bào)錯(cuò)
給變量指定默認(rèn)值
- 如果輪不到賦值,則默認(rèn)值生效:
let [a,b = 3] = [1];
console.log(b); // 3
- 如果輪到賦值堰乔,但賦給的是undefined偏化,則默認(rèn)值生效:
let [x, y = '3'] = ['1', undefined];
console.log(y); // 3
如果默認(rèn)值是表達(dá)式,那么只有它真的會(huì)被賦值镐侯,js才會(huì)去計(jì)算這個(gè)表達(dá)式侦讨,如果它沒有被賦值,那么js為了系統(tǒng)性能考慮苟翻,不會(huì)去計(jì)算這個(gè)表達(dá)式韵卤。
如果默認(rèn)值是其他變量,那么要注意這個(gè)變量是否已經(jīng)存在崇猫。比如:
let [x = y, y = 1] = []; // ReferenceError: y is not defined
給x賦值的時(shí)候沈条,y還不存在,當(dāng)然報(bào)錯(cuò)诅炉。
對(duì)象的解構(gòu)賦值
基本用法
屬性名匹配成功蜡歹,就賦值屋厘,不成功就不賦值。不賦值默認(rèn)也是undefined月而。
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
復(fù)雜用法
跟數(shù)組解構(gòu)差不多汗洒,但是對(duì)象的解構(gòu)賦值沒有剩余符號(hào)的這一說。
引用不匹配的屬性值
比如我的變量名跟對(duì)象的屬性名恰好不一致父款,但確實(shí)希望變量得到該屬性值溢谤,怎么辦?就像這樣憨攒,寫成a:c
溯香,c是你寫的變量名,a:c
表示:雖然我變量名不叫a而是叫c浓恶,但是我希望c得到a屬性的值玫坛。
let { a: c } = { a: 'aaa', b: 'bbb' };
c // "aaa"
深度賦值
let { b: {c} } = { b: {c: 'ccc'} };
console.log(c); // ccc
let { b: {c: d} } = { b: {c: 'ccc'} };
console.log(d); // ccc
看出端倪了么?其實(shí)包晰,
let { a, b } = { a: "aaa", b: "bbb" }
就可以理解為:
let { a: a, b: b } = { a: "aaa", b: "bbb" }
然后對(duì)應(yīng)賦值就可以了湿镀,冒號(hào)后面才是變量名,冒號(hào)前面就是“線索”伐憾,按照線索找值就行了勉痴。
對(duì)象解構(gòu)賦值跟數(shù)組解構(gòu)賦值的鮮明對(duì)比:
let { b, b: {c: d} } = { b: {c: 'ccc'} };
console.log(d); // ccc
console.log(b); // {c: "ccc"}
對(duì)象解構(gòu)賦值,不像數(shù)組解構(gòu)賦值那樣排排隊(duì)树肃,然后挨個(gè)賦值蒸矛,而是每次都根據(jù)“線索”找值,能找到就找到胸嘴,找不到就undefined雏掠。
數(shù)組和對(duì)象混合嵌套賦值
無論怎么混合嵌套,只需要知道劣像,模式匹配就行乡话。模式匹配最重要!耳奕!
let [a, { b: c }] = ['aaa', { b: 'bbb' }];
console.log(c); // bbb
console.log(a); // aaa
let { b,b: {c: [d, e]} } = { b: {c: ['ddd', 'eee']} };
console.log(b); // {c: ['ddd', 'eee']}
console.log(d); // ddd
console.log(e); // eee
提醒注意绑青,并沒有定義一個(gè)叫c的變量,試圖輸出c肯定會(huì)出錯(cuò)屋群。
默認(rèn)值
也是用賦值號(hào)=
賦值闸婴,跟數(shù)組一樣道理。
大括號(hào)寫在行首的陷阱
let x;
{x} = {x: 1};
// SyntaxError: syntax error
上栗芍躏,你以為能給x賦值1邪乍,但是其實(shí)不行,因?yàn)榇罄ㄌ?hào)寫在行首,被js認(rèn)為是代碼塊溺欧,而不是賦值的語法符號(hào),所以柏肪,要么大括號(hào)別寫在行首姐刁,要么,整體包在括號(hào)里:
let x;
({x} = {x: 1});
x; // 1
把數(shù)組當(dāng)對(duì)象解構(gòu)
數(shù)組也是有下標(biāo)的烦味,當(dāng)然可以當(dāng)做對(duì)象結(jié)構(gòu):
let {0: x, 2: z} = ['a', 'b', 'c'];
console.log(x,z); // a c
字符串的解構(gòu)賦值
很簡(jiǎn)單聂使,字符串可以被拆開當(dāng)做數(shù)組來解構(gòu)。
let [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
由于類似數(shù)組的對(duì)象都天然有一個(gè)length屬性谬俄,因此還可以對(duì)這個(gè)屬性解構(gòu)賦值柏靶。
let {length : len} = 'hello';
len // 5
數(shù)值和布爾值的解構(gòu)賦值
數(shù)值、布爾值不像字符串能拆成數(shù)組來解構(gòu)溃论,沒討論意義屎蜓。
函數(shù)參數(shù)的解構(gòu)賦值
這個(gè)用處就很大了,甚至可以說是解決了之前js世界的函數(shù)參數(shù)的天生缺陷钥勋。
什么缺陷呢炬转?js之前只能這么傳參,這種傳參的缺陷是算灸,你需要傳5個(gè)參數(shù)扼劈,往往這5個(gè)參數(shù)來自于一個(gè)數(shù)組,于是你必須事先把這個(gè)數(shù)組拆開成5個(gè)變量菲驴,然后分別傳進(jìn)去:
function f(a,b,c,d,e) {
return a + b + c + d + e;
}
f(19, 19, 19, 19, 19); // 95
如果你強(qiáng)行想要一次性傳入一個(gè)數(shù)組[19,19,19,19,19]荐吵,那就有點(diǎn)小麻煩,只能這樣赊瞬,這樣的缺陷就是用下標(biāo)表示變量先煎,不夠直觀:
function f(arr) {
return arr[0] + arr[1] + arr[2] + arr[3] + arr[4];
}
f([19, 19, 19, 19, 19]); // 95
現(xiàn)在ES6之后,你就可以傳入一個(gè)數(shù)組作為一套參數(shù)巧涧,js幫你自動(dòng)解構(gòu):
function f([a,b,c,d,e]) {
return a + b + c + d + e;
}
f([19, 19, 19, 19, 19]); // 95
默認(rèn)值
函數(shù)參數(shù)也可以有默認(rèn)值榨婆,都是一樣的。數(shù)組元素可以空著褒侧,也可以寫undefined良风,但不能寫null,null被認(rèn)為是有值闷供。
function f([a,b,c = 100,d,e]) {
return a + b + c + d + e;
}
f([1, 1, , 1, 1]); // 104
變量解構(gòu)賦值的優(yōu)點(diǎn)匯總
變量解構(gòu)賦值其實(shí)在其他語言都早已實(shí)現(xiàn)烟央,只是ES實(shí)現(xiàn)的太晚了,它的優(yōu)點(diǎn)有很多歪脏,比如:
- 賦值語句干凈疑俭,簡(jiǎn)短,直觀婿失。
- 交換變量的值的最佳方法:
let x = 1;
let y = 2;
[x, y] = [y, x];
- 對(duì)數(shù)組和對(duì)象快速取值钞艇,這是實(shí)踐中最常用的用途啄寡,尤其是從服務(wù)器傳來的JSON,結(jié)構(gòu)可能相當(dāng)復(fù)雜哩照,從前你要寫多行語句來獲取其中的每一個(gè)屬性挺物,現(xiàn)在就簡(jiǎn)單的一逼了。
比如:
var json_from_server = [
{
name: 'zhang',
age: 16
},
{
name: 'wang',
age: 23
},
];
var [{name: a, age:b}, {name:c, age: d}] = json_from_server;
console.log(a,b,c,d); // zhang 16 wang 23
如果不用結(jié)構(gòu)賦值飘弧,要怎么寫呢识藤?如下:
var json_from_server = [
{
name: 'zhang',
age: 16
},
{
name: 'wang',
age: 23
},
];
var a = json_from_server[0]['name'];
var b = json_from_server[0]['age'];
var c = json_from_server[1]['name'];
var d = json_from_server[1]['age'];
console.log(a,b,c,d); // zhang 16 wang 23
是不是代碼很冗余?
- 就像上面說的次伶,函數(shù)參數(shù)能解構(gòu)痴昧,所以參數(shù)名既能保持語義,又能當(dāng)做數(shù)組一次性傳入冠王。
- 默認(rèn)值可以直接在賦值語句里定義赶撰,就不用像以往那樣專門寫一行語句來設(shè)定默認(rèn)值,干凈了很多柱彻。
- 函數(shù)參數(shù)也能設(shè)定默認(rèn)值扣囊,就不用在函數(shù)體內(nèi)判斷參數(shù)是否存在,然后決定設(shè)不設(shè)默認(rèn)值绒疗,省卻很多麻煩侵歇。