對象和數組字面量是JavaScript中兩種最常用的數據結構,由于JSON數據結構的普及绽诚,兩者已經成為語言中特別重要的一部分拯勉。在編碼過程中,我們經常定義許多對象和數組憔购,然后有組織地從中提取相關的信息片段宫峦。ES6添加了可以簡化這種任務的新特性:解構。
為何使用解構功能
在ES5中玫鸟,開發(fā)者為了從對象和數組中獲取特定數據并賦值給變量导绷,編寫了很多同質化代碼。
let options={
repeat: true,
save: false
};
//從對象中提取數據
let repeat=options.repeat,
save=options.save;
這段代碼中從options中提取repeat和save的值并存儲的過程十分相似屎飘,如果需要得到的值很多妥曲,則會編寫很多次同質化代碼贾费,如果代碼中海油嵌套結構,則會非常麻煩檐盟。
所以ES6為對象和數組都添加了結構功能褂萧,將數據結構打散過稱變得很簡單,使我們更容易獲取信息葵萎。
對象解構
對象字面量的語法形式是在一個賦值操作符左邊放置一個對象字面量导犹。
let node={
type:"Indetifier",
name:"foo"
};
let {type,name}=node;
console.log(type);//"Indetifier"
console.log(name);//"foo"
在這段代碼中,node.type的值存儲在名為type的變量中羡忘;node.name的值存儲在名為name的變量中谎痢。
值得注意的是:如果用var、let和const解構聲明變量卷雕,則必須要為其初始化节猿,否則報錯。
//語法錯誤
var {type,name};
//語法錯誤
let {type,name};
//語法錯誤
const {type,name};
解構賦值
我們同樣可以在給變量賦值時使用解構語法漫雕。
let node={
type:"Indetifier",
name:"foo"
},
type="Literal",
name=5;
({type,name}=node);
console.log(type);//"Indetifier"
console.log(name);//"foo"
在示例中滨嘱,聲明type和name時初始化了一個值,在后面通過結構重新賦值浸间。需要注意的地方是:因為開放的{}會被視為代碼塊太雨,而語法規(guī)定,代碼塊不允許出現在賦值語句左邊发框,所以需要加小括號使其轉化為一個表達式躺彬。
結構表達式的值與表達式右側(也就是=右側)的值相等煤墙,如此在任何可以使用值得地方你都可以使用解構賦值表達式梅惯。
let node={
type:"Indetifier",
name:"foo"
},
type="Literal",
name=5;
function outputInfo(value){
console.log(value==node);//true
}
console.log(type);//"Indetifier"
console.log(name);//"foo"
值得注意的點是:如果右側的值為null或undefined會導致程序拋出錯誤。也就是嘗試讀取null和undefined的屬性的行為都會拋出錯誤仿野。
默認值
如果指定的局部變量名稱在對象中不存在铣减,那么這個局部變量會被賦值undefined。
let node={
type:"Indetifier",
name:"foo"
};
let {type,name,value}=node;
console.log(type);//"Indetifier"
console.log(name);//"foo"
console.log(value);//"undefiined"
當指定屬性不存在時脚作,可以隨意定義一個默認值葫哗。
let node={
type:"Indetifier",
name:"foo"
};
let {type,name,value=true}=node;
console.log(type);//"Indetifier"
console.log(name);//"foo"
console.log(value);//"true"
為非同名局部變量賦值
如果希望用不同命名的局部變量來存儲對象屬性的值,可以這樣寫球涛。
let node={
type: "Identifier",
name: "foo"
};
let {type: localType,name: localName}=node;
console.log(localType);//"Identifier"
console.log(localName);//"foo"
這段代碼使用了解構聲明來聲明變量localType和localName劣针,這兩個量分別包含node.type和node.name的值,
當使用其他變量名進行賦值時也可以為其添加默認值亿扁。
let node={
type: "Identifier",
};
let {type: localType="hahaha",name: localName="ccg"}=node;
console.log(localType);//"Identifier"
console.log(localName);//ccg
嵌套對象解構
let node={
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
}
};
let {loc:{start}}=node;
console.log(start.line);//1
console.log(start.column);//1
在這個示例中捺典,我們在解構模式中使用了花括號,其含義是在找到node對象的loc屬性后从祝,深入一層找到start屬性襟己。
更近一步引谜,可以使用一個與對象屬性名不同的局部變量名:
let node={
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
}
};
let {loc:{start: localStart}}=node;
console.log(localStart.line);//1
console.log(localStart.column);//1
對象解構功能很好用,但是值得注意的是擎浴,你可能會創(chuàng)建一個無效表達式员咽,它是合法的,但是什么都干不了贮预。
//未申明任何變量
let {loc:{}}=node;
左邊的loc不是即將創(chuàng)建的綁定贝室,只是代表對象中的檢索屬性的位置。
數組解構
與對象解構的語法相比萌狂,數組解構就簡單多了档玻,它使用的是數組字面量,且解構操作全部在數組內完成茫藏,而不是像對象字面量語法一樣使用對象的命名屬性:
let colors=["red","green","blue"];
let [firstColor,secondColor]=colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"
在這段代碼中误趴,我們從colors數組中解構出“red”和“green”這兩個值,并分別存儲在變量firstColor和變量secondColor中务傲。在數組解構語法中凉当,我們通過值在數組的位置進行選取,且可以將其存儲在任意變量中售葡,未顯式申明的元素會被忽略哦看杭。值得注意的是,這個過程中數組不會發(fā)生任何變化挟伙。
在解構模式中楼雹,也可以直接省略元素,只為需要的元素提供變量名尖阔。
let colors=["red","green","blue"];
let [ , , thirdColor]=colors;
console.log(thirdColor);//"blue"
thiirdColor前的逗號是前方元素的占位符贮缅,無論數組元素有多少個,你都可以通過這種方式提取需要的元素介却,并不需要額外指定變量名谴供。
值得注意的是:使用var、let和const聲明數組解構的綁定時齿坷,必須要提供一個初始化程序桂肌。
解構賦值
數組解構也可以用于賦值上下文,但不需要用小括號包裹表達式永淌,這一點與數組解構的約定不同崎场。
let colors=["red","green","blue"],
firstColor="black",
secondColor="purple";
[firstColor,secondColor]=colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"
解構語法中還有一個特例:交換兩個變量的值。
//在es5中交換變量
let a=1,
b=2,
tmp;
tmp=a;
a=b;
b=tmp;
console.log(a);//2
console.log(b);//1
//如果使用數組解構賦值語法遂蛀,就不需要用額外的變量了谭跨。
//在ES6中交換變量
let a=1,
b=2;
[a,b]=[b,a];
console.log(a);//2
console.log(b);//1
代碼執(zhí)行過程中:先解構臨時數組,將b和a的值復制到左側數組的前兩個位置,最終結果是變量互換了它們的值饺蚊。
值得注意的是:如果右側數組解構賦值表達式的值為null或undefined萍诱,則會導致程序 拋出錯誤。
默認值
也可以在數組解構賦值表達式中為數組中的任意位置添加默認值污呼,當指定位置的屬性不存在或其值為undefined時使用默認值:
let colors=["red"];
let [firstColor,secondColor="green"]=colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"
嵌套數組解構
在原有的數組模式中插入另一個數組模式裕坊,即可將解構過程深入到下一層次:
let colors=["red",["green","lightgreen"],"blue"];
//接下來
let [firstColor,[secondColor]]=colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"
不定元素
數組解構中也可以用不定元素。
let colors=["red","green","blue"];
let [firstColor,...restColors]=colors;
console.log(firstColor);//"red"
console.log(restColors.length);//2
console.log(restColors[0]);//"green"
console,log(restColors[1]);//"blue"
數組復制
//在ES5中克隆數組
var colors=["red","green","blue"];
var clonedColors=colors.concat();//concat()設計初衷是用于連接兩個數組燕酷,當不傳遞 參數時就會返回當前的副本籍凝。
console.log(clonedColors);//
//在ES6中的新方法
let colors=["red","green","blue"];
let [...clonedColors]=colors;
console.log(clonedColors);//"[red,green,blue]"
比較這個方法和concat()方法的可讀性,喜歡用哪個你就用哪個吧苗缩。QAQ...
值得注意的是在被解構的數組中饵蒂,不定元素必須為最后一個條目,在后面添加逗號會報錯酱讶。
混合解構
可以混合使用對象解構和數組解構來創(chuàng)建更多復雜的表達式退盯。
let node={
type:"Indentifier",
name:"foo",
loc:{
start:{
line:1,
column:1
},
end:{
line:1,
column:4
}
},
range:[0,3]
};
let {
loc:{start},
range:[startIndex]
}=node;
console.log(start.line);//1
console.log(start.column);//1
console.log(startIndex);//0
解構參數
解構可以用在函數參數的傳遞過程中,這種特別方式更特別泻肯。當定義接受大量可選參數的JavaScript函數時渊迁,我們通常會創(chuàng)建一個可選對象,將額外的參數定義為這個對象的屬性灶挟。
//options的屬性表示其他參數
function setCookie(name,value,options){
options=options||{};
let secrue=options.secrue,
path=options.path,
domain=options.domain,
expires=options.expires;
//設置cookie的代碼
}
//第三個參數映射到options中
setCookie("type","js",{
secrue:true,
expires:60000
});
這樣的setCookie存在的問題是僅查看函數的聲明部分琉朽,無法辨識函數的預期函數,必須閱讀函數體才可以確定所有參數的情況稚铣。
定義為解構函數就可以解決這個問題箱叁。
function setCookie(name,value,{secrue,path,domain,expires}){
//設置cookie的代碼
}
//第三個參數映射到options中
setCookie("type","js",{
secrue:true,
expires:60000
});
必須傳值的解構參數
解構函數有個奇怪的地方,默認情況下惕医,如果調用函數時不提供被解構的參數會導致程序拋出錯誤耕漱。
setCookie("type","js");//程序報錯
缺失的第三個參數,其值為undefined曹锨,而解構參數只是將解構聲明應用到在函數參數的一個寫法孤个,其會導致程序拋出錯誤剃允。當調用setCookie()函數時沛简,JavaScript引擎實際上做了這些事情:
function setCookie(name,value,options){
let {secure,path,domain,expires}=options;
//設置cookie的代碼
}
如果解構表達式的右邊為null或undefined,則程序會報錯斥废,同理椒楣,調用時不傳參數也會報錯。
如果希望解構函數參數可選牡肉,可以這樣寫:
function setCookie(name,value,{secure,path,domain,expires}={}){
//...
}
解構參數的默認值
可以為解構函數指定默認參數值捧灰,就像在解構賦值語句中一樣,只需要添加默認值就好了。
function setCookie(name,value,{
secure=false,
path="/",
domain="example.com",
expires=new Date(Date.now()+360000000)
}){
//...
}
這種方法看著挺清晰毛俏,但是函數聲明比以前復雜炭庙,這里建議直接用相同的解構作為默認參數:
function setCookie(name,value,{
secure=false,
path="/",
domain="example.com",
expires=new Date(Date.now()+360000000)
}={
secure=false,
path="/",
domain="example.com",
expires=new Date(Date.now()+360000000)
}
){
//...
}
現在函數變得更加完整了,第一個對象字面量是解構參數煌寇,第二個為默認值焕蹄,為了解決部分代碼冗余,可以將默認值封裝在一個獨立對象中阀溶。
const setCookDefaults={
secure=false,
path="/",
domain="example.com",
expires=new Date(Date.now()+360000000)
};
function setCookie(name,value,{
secure=false,
path="/",
domain="example.com",
expires=new Date(Date.now()+360000000)
}=setCookieDefaults
){
//...
}
在這段代碼中腻脏,默認值已經被放到setCookieDefaults對象中,除了作為默認參數值银锻,在解構參數中可以直接使用這個對象為每一個綁定設置默認值永品。使用解構參數后缤骨,不得不處理默認參數的復雜邏輯放祟,但它也有好的一面箍铲,如果要改變默認值竖伯,可以立即在setCookieDefaults中修改师枣,改變的值將自動同步到所有出現過的地方铃慷。