作者:米書林
參考文章:《菜鳥教程》椅贱、《 ECMAScript 6 入門》(阮一峰)
解構(gòu)的定義
????ES6 允許按照一定模式,從數(shù)組和對象中提取值只冻,對變量進(jìn)行賦值庇麦,這被稱為解構(gòu)。
結(jié)構(gòu)表達(dá)式的組成
1.解構(gòu)的源:解構(gòu)表達(dá)式值的來源喜德,表達(dá)式的右邊部分
2.解構(gòu)的目標(biāo):定義解構(gòu)表達(dá)式值的存儲變量山橄,表達(dá)式的左邊部分
數(shù)組的解構(gòu)
基本用法
let [a,b,c] = [1,2,3];
console.log(a); \\ 1
console.log(b); \\ 2
console.log(c); \\ 3
????只要表達(dá)式左右的結(jié)構(gòu)一樣,左邊對應(yīng)的變量能在右邊找到對應(yīng)的值住诸,就能將右邊的值賦值給左邊的變量驾胆。
????我們可以用解構(gòu)賦值來簡化后臺給我們傳遞的數(shù)據(jù),減少數(shù)據(jù)遍歷的循環(huán)次數(shù)
可嵌套
let [a, [[b], c]] = [1, [[2], 3]];
// a = 1
// b = 2
// c = 3
若上述變量b不用[]括起來贱呐,則b返回的值帶有中括號丧诺,如下:
let [a, [b, c]] = [1, [[2], 3]];
// a = 1
// b = [2]
// c = 3
可忽略
let [a, , b] = [1, 2, 3];
// a = 1
// b = 3
若被忽略項在末尾,直接忽略奄薇;若被忽略項不在末尾驳阎,則需要用","來填補(bǔ),若省略",",則瀏覽器默認(rèn)會在末尾補(bǔ)齊
例如:
let [a, , b] = [1, 2, 3, 4];
// a = 1
// b = 3
let [a, , , b] = [1, 2, 3, 4];
// a = 1
// b = 4
不完全解構(gòu)
let [a = 1, b] = [];
// a = 1
// b = undefined
若定義的變量在右側(cè)無對應(yīng)項呵晚,則會被賦值為:undefined
;
若定義的變量給定默認(rèn)值蜘腌,且匹配結(jié)果為undefined
,則解構(gòu)的結(jié)果為默認(rèn)值。
剩余運(yùn)算符
let [a, ...b] = [1, 2, 3];
//a = 1
//b = [2, 3]
注意:含有剩余運(yùn)算符項表達(dá)式要放在最后一項
結(jié)構(gòu)源為字符串
let [a,b,c] = "ES6"
// a = "E"
// b = "S"
// c = "6"
解構(gòu)默認(rèn)值
????當(dāng)解構(gòu)模式有匹配結(jié)果饵隙,且匹配結(jié)果是 undefined 時撮珠,會觸發(fā)默認(rèn)值作為返回結(jié)果。
let [a = 3, b = a] = [undefined]; // a = 3, b = 3
let [a = 3, b = a] = [1]; // a = 1, b = 1
let [a = 3, b = a] = [1, 2]; // a = 1, b = 2
分析:
????第一個表達(dá)式a匹配的結(jié)果為undefined
,故返回a的默認(rèn)值金矛,a的默認(rèn)值為3芯急,b匹配的結(jié)果為undefined
,故返回b的默認(rèn)值,b的默認(rèn)值為b=a,a此時為3驶俊,故b為3娶耍;
????第二個表達(dá)式a匹配的結(jié)果為1,故返回a的匹配值1,b匹配的結(jié)果為undefined
,故返回b的默認(rèn)值饼酿,b的默認(rèn)值為b=a,a此時為1榕酒,故b為1;
????第三個表達(dá)式a匹配的結(jié)果為1,故返回a的匹配值1故俐,b匹配的結(jié)果為2,故返回b的匹配值2想鹰;
解構(gòu)匹配值為null
let [a=12] = [null]
// a = null
解構(gòu)Set結(jié)構(gòu)
let [a, c, c] = new Set(['a', 'b', 'c']);
// a = "a"
// b = "b"
// c = "c"
不只是數(shù)組,只要能遍歷的結(jié)構(gòu)都能使用解構(gòu)
不能遍歷的結(jié)構(gòu)不能被解構(gòu)购披,例如:
let [a] = 1;
let [a] = false;
let [a] = NaN;
let [a] = undefined;
let [a] = null;
let [a] = {};
以上代碼瀏覽器執(zhí)行后都會報錯杖挣。
對象模型的解構(gòu)
基本
let {name,age} = {name:"張三",age:20}
// name = "張三"
// age = 20
注意:此處等號左側(cè)的變量name是name:name縮寫,age是age:age的縮寫刚陡,ES6新特性規(guī)定對象的屬性和值用同一變量可以簡寫為一個惩妇。因此:結(jié)構(gòu)后的結(jié)果實際上是賦值給了對象屬性值的變量
對象屬性值的解構(gòu)
let {name:name1} = {name:"李四"}
// name = undefined(瀏覽器報錯:name is not defined)
// name1 = "李四"
上面代碼可以看出解構(gòu)的結(jié)果賦值給了對象屬性值對應(yīng)的變量
可嵌套
let {p: [x, { y }] } = {p: ['hello', {y: 'world'}] };
// x = 'hello'
// y = 'world'
可忽略
let {p: [x, { }] } = {p: ['hello', {y: 'world'}] };
// x = 'hello'
let {p: [, { y }] } = {p: ['hello', {y: 'world'}] };
// y = 'world'
不完全解構(gòu)
let {p: [{ y }, x ] } ={p: [{y: 'world'}] };
// x = undefined
// y = 'world'
剩余運(yùn)算符
let {a, b, ...rest } = {a: "張三", b: "李四", c: "王五", d: "李二"};
// a = "張三"
// b = "李四"
// rest = {c: "王五", d: "李二"}
解構(gòu)默認(rèn)值
let {a = 1, b = 2} = {a: 3};
// a = 3; b = 2;
let {a: aa = 10, b: bb = 5} = {a: 3};
// aa = 3; bb = 5;
默認(rèn)解構(gòu)值在匹配結(jié)果為undefined
時觸發(fā)。
已經(jīng)聲明的變量用于解構(gòu)賦值
// 錯誤的寫法
let x;
{x} = {x: 1};
// Uncaught SyntaxError: Unexpected token '='
以上代碼瀏覽器會報錯筐乳,原因是瀏覽器將大括號解析成了代碼塊歌殃,兩個代碼塊之間要么為空格,要么為“;”,故此處報錯蝙云。解決的辦法是用()將它轉(zhuǎn)換成一個表達(dá)式
let x;
({x} = {x: 1});
應(yīng)用場景
1.任意個參數(shù)求和
傳統(tǒng)方法:
????js傳統(tǒng)方法需要借助arguments來實現(xiàn)氓皱,具體方法如下:
function sum(){
var sum = 0;
var len = arguments.length; // 將長度存儲在變量中可以減少循環(huán)次數(shù),提升性能
for(var i = 0;i < len;i++){
sum +=arguments[i]
}
return sum;
}
sum(1,2,3); // 6
sum(1,2,"4"); // "34"
此處只是為了對比傳統(tǒng)方法和ES6新方法求和勃刨,未作數(shù)值類型轉(zhuǎn)化波材,故第二個調(diào)用出現(xiàn)了字符串拼接
ES6新方法:
????ES6用剩余項表達(dá)式和解構(gòu)來存儲參數(shù)個數(shù),求和的方法如下:
function sum(...nums){
let sum = nums.reduce((x,y)=>{return x+y})
return sum
}
sum(1,2,3); // 6
sum(1,2,"4"); // "34"
注意此處使用了ES6數(shù)組的新方法:reduce身隐,reduce的作用是匯總廷区,輸入一堆,輸出一個結(jié)果
????在這里我們可能感覺兩種方法的實現(xiàn)原理好像是一樣的額贾铝,其實并不然隙轻,傳統(tǒng)方法借助的arguments是一個類數(shù)組埠帕,雖然我們可以像數(shù)組一樣用下標(biāo),即arguments[0],arguments[1]
,...的方式去訪問它玖绿,也能通過arguments.length
來計算傳入?yún)?shù)的個數(shù)敛瓷,還能使用arguments.callee
(注意在ES5中這個屬性已被廢棄,caller
不是的屬性)斑匪,然而它還是沒有數(shù)組常用的一些方法呐籽,比如reduce,pop,push,shift,unshift
等,所以用傳統(tǒng)方法求參數(shù)和要比ES6的代碼多好幾行秤标。
2.不借助第三個參數(shù)交換變量的值
傳統(tǒng)方法:
????傳統(tǒng)方法(ES6之前绝淡,C語言等)要交換兩個變量的值需要借助第三個變量,在js中的實現(xiàn)方法大概如下:
let a = 1;
let b = 2;
let c = a;
console.log(a,b,c);
a = b;
b = c;
// a = 2;
// b = 1;
// c = 1;
所以苍姜,傳統(tǒng)方法大概需要5行代碼才能實現(xiàn)。
ES6方法:
ES6中我們不需要借助第三個參數(shù)悬包,具體實現(xiàn)方法如下:
let a = 1;
let b = 2;
[a, b] = [b, a];
// a = 2;
// b = 1;
從上面可以看出我們只需要三行代碼就能完成參數(shù)的交換衙猪。
3.收集函數(shù)的剩余參數(shù),用作公共函數(shù)可選項
????我們都知道js中傳遞的實參可以不和形參一一對應(yīng);
????形參個數(shù)大于實參個數(shù)時布近,多余的形參會被初始化為undefined
(函數(shù)聲明整體提升垫释,隨后找形參并將形參初始化為undefined,最后才是實參和形參相統(tǒng)一撑瞧,所以沒有實參對應(yīng)的形參值仍然是undefined)棵譬;
????當(dāng)形參個數(shù)小于實參個數(shù)時,多余的實參會被忽略预伺;
????因此订咸,一些場景下即使我們只用到一次的或者可能不會用到的參數(shù)都要在定義形參來傳遞,一些參數(shù)個數(shù)不確定的場景下我們只能通過多定義形參來解決問題酬诀,但是這顯然有些笨拙脏嚷。
????在ES6新特性中,我們可以通過“...+變量名”來解決參數(shù)傳遞的問題瞒御。
????下面我們可以通過函數(shù)來簡單模范api的可選參數(shù)父叙,我們把必填參數(shù)放在前面,把可選參數(shù)放在剩余項里肴裙,這樣我們的代碼如下:
function dateFormat(a,..b){
...
}
????上面代碼a是必填參數(shù)趾唱,b是可選參數(shù)的集合,這樣我們就能通過一個變量將不常用的參數(shù)放到一個集合中了蜻懦。
4.返回多個函數(shù)結(jié)果
????ES6之前我們想從函數(shù)返回多個結(jié)果甜癞,只能將它們放在數(shù)組或?qū)ο罄锓祷兀胍@取每一個返回結(jié)果阻肩,少不了循環(huán)和遍歷語句带欢,這很讓人頭疼运授。
????有了ES6后我們就可以將函數(shù)執(zhí)行的結(jié)果一個一個的提取出來。大概的代碼如下:
// 返回一個數(shù)組
function test() {
return [1, 2, 3];
}
let [a, b, c] = test();
// 返回一個對象
function test() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = test();
5.簡化底層數(shù)據(jù)的調(diào)用
????很多時候后臺返回給我們的都是一些對象和數(shù)組的混合嵌套體乔煞,對于深層數(shù)據(jù)的訪問我們往往需要寫一長串“.”引用吁朦,用解構(gòu)賦值我們就可以將這些數(shù)據(jù)單獨(dú)獲取出來。
6.設(shè)置函數(shù)參數(shù)的默認(rèn)值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};
指定參數(shù)的默認(rèn)值渡贾,就避免了在函數(shù)體內(nèi)部再寫var foo = config.foo || 'default foo';
這樣的語句逗宜。
7.遍歷 Map 結(jié)構(gòu)
任何部署了 Iterator 接口的對象,都可以用for...of循環(huán)遍歷空骚。Map 結(jié)構(gòu)原生支持 Iterator 接口纺讲,配合變量的解構(gòu)賦值,獲取鍵名和鍵值就非常方便囤屹。
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
如果只想獲取鍵名熬甚,或者只想獲取鍵值,可以寫成下面這樣肋坚。
// 獲取鍵名
for (let [key] of map) {
// ...
}
// 獲取鍵值
for (let [,value] of map) {
// ...
}
8.輸入模塊的指定方法
加載模塊時乡括,往往需要指定輸入哪些方法。解構(gòu)賦值使得輸入語句非常清晰智厌。
const { SourceMapConsumer, SourceNode } = require("source-map");