在正式的講解以前,咱們先來分析一下,到底什麼是解構賦值? 經過對詞組的分析,咱們大體能理解,解構---也就是破壞,破壞原來的結構,賦值---固然就是再次賦值。下面咱們來具體的分析一下,到底什麼是解構賦值。javascript
ES6容許按照必定模式從數組和對象中提取值,而後對變量進行賦值,這被稱做解構(Destructuring)。 之前,爲變量賦值只能直接指定值。java
let a = 1;
let b = 2;
let c = 3;
複製代碼
ES6容許寫成這樣。node
let [a,b,c] = [1,2,3]
複製代碼
上面的代碼表示,能夠從數組中提取值,按照對應的位置進行變量賦值。 本質上,這種寫法屬於「模式匹配」,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。下面是一些使用嵌套數組進行解構的例子。es6
let [foo, [[bar], baz]] = [1,[[2],3]];
foo //1 ;
bar //2 ;
baz //3 ;
let [ , , third] = ["foo", "bar", "baz"];
third //"baz"
let [x, , z] = [1,2,3];
x //1
z //3
let [head, ...tail] = [1,2,3,4];
head // 1
tail // [2,3,4]
let [x, y, ...z] = ["a"];
x //"a"
y // undefined
z //[]
複製代碼
若是解構不成功,變量的值就等於undefined。json
let [foo] = [];
let [bar, foo] = [1];
複製代碼
上面的foo取值都是會等於undefined. 另外一種狀況是不徹底解構,即等號左邊的模式只匹配一部分等號右邊的數組,這種狀況,解構依然能夠成功。數組
let [x, y] = [1,2,3];
x //1;
y //2;
let [a, [b], c] = [1, [1,3], 4];
a //1
b //1
c //4
複製代碼
上面的例子屬於不徹底解構,可是能夠成功。 若是等號的右邊不是數組,嚴格來講是不可遍歷的結構,那麼將會報錯。數據結構
let [foo] = 1;
let [foo] = false;
let [foo] = undefined;
let [foo] = NaN;
let [foo] = null;
let [foo] = {};
複製代碼
上面的語句會報錯,由於等號右邊的值或者是轉換爲對象之後不具有Iterator接口,或者自己就不具有Iterator接口。(最後一個表達式) 簡單的介紹一下Iterator接口。 遍歷器(Iterator)是一種接口,爲各類不一樣的數據結構提供統一的訪問機制,任何數據結構,只要部署Iterator接口,就能夠完成遍歷操做。 如下數據結構具有原生的Iterator接口。(可以使用for...of方法進行循環遍歷)函數
let [x,y,z] = new Set(["a","b","c"]);
x// "a"
var map = new Map();
map.set("first","hello");
map.set("second","world");
for(let [key, value] of map){
console.log(key +" is " + value);
}
複製代碼
解構賦值容許指定默認值。ui
let [foo = true] = [];
foo //true
let [x,y = 'b'] = ['a'];
x //'a';
y //'b';
let [x, y = 'b'] = ['a', undefined];
x // 'a'
y // 'b'
複製代碼
ES6內部使用嚴格相等運算符(===)判斷一個位置是否有值。因此,若是一個數組成員不嚴格等於undefined,默認值不會生效。spa
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x //null
複製代碼
上面的第二個例子沒有取到默認值,是由於null不嚴格等於undefined。 並且,須要注意的是,默認值能夠引用解構賦值的其餘變量,但該變量必須已經聲明。
let [x = 1, y = x] = []; //x =1 y = 1
let [x = 1, y = x] = [2]; // x = 2 y = 2
let [x = 1, y = x] = [1,2]; // x = 1 y = 2
let [x = y, y = 1] = []; //ReferenceError
複製代碼
最後一個報錯,是由於,x用到默認值y時,y尚未聲明。
解構賦值不只能夠用於數組,還能夠用於對象。
let {foo, bar} = {foo:"aaa", bar: "bbb"};
foo // "aaa"
bar // "bbb"
複製代碼
對象的解構賦值與數組有一個重要的不一樣。數組的元素是按次序排列的,變量的取值是由它的位置決定的,而對象的屬性沒有次序,變量必須與屬性同名才能取到正確的值
let {foo, bar} = {bar: "bbb", foo:"aaa"};
foo // "aaa"
bar // "bbb"
let {baz} = {bar: "bbb", foo:"aaa"};
baz //undefined
複製代碼
上面的代碼就驗證了,取值與次序無關。 第二個例子沒有取到值,是由於變量沒有對應的同名屬性,致使取不到值,最後等於undefined。 若是變量與屬性名不一致,必需要寫成下面這樣,
let {foo:baz} = {bar: "bbb", foo:"aaa"};
baz //"aaa"
let obj = {first: "hello", last: "world"};
let {firt: f, last: l} = obj;
f // "hello"
l // "world"
複製代碼
重點來了,實際上,對象的解構賦值是下面的簡寫
let {foo: foo, bar: bar} = {foo:"aaa", bar: "bbb"};
複製代碼
也就是說,對象的解構賦值的內部機制是先找到同名屬性,而後再賦值給對應的變量。真正被賦值的是後者,而不是前者。
let {foo:baz} = {bar: "bbb", foo:"aaa"};
baz //"aaa"
foo // foo is not defined
複製代碼
上面的代碼中,***foo是匹配的模式,baz纔是變量。真正被賦值的是變量baz,而不是模式foo。***
與數組同樣,解構也能夠用於對嵌套結構的對象。
複製代碼
let obj = {
p:[
'hello',
{y: 'world'}
]
};
let {p: [x,{y}]} = obj;
x // "hello"
y // "world"
複製代碼
注意這時,p是模式,不是變量,所以不會被賦值,若是p也要做爲變量被賦值,能夠寫成下面這樣,
let obj = {
p:[
'hello',
{y: 'world'}
]
};
let {p,p: [x,{y}]} = obj;
x // "hello"
y // "world"
p // p:['hello', {y: 'world'}]
複製代碼
另外一個例子,
var node = {
loc:{
start : {
line: 1,
column: 5
}
}
};
var {loc, loc:{start}, loc:{start: {line}}} = node;
line // 1
loc // Object {start : Object }
start // Object {line: 1, column:5}
複製代碼
上面的代碼有三次解構賦值,分別是對loc,start,line三個屬性的解構賦值。須要注意的是,最後一次對line屬性的解構賦值之中,只有line是變量,loc和start都是模式。
若是將一個已聲明的變量進行賦值時,必定要當心了!
//錯誤寫法
let x
{x} = {x:1};
//syntaxError: syntax error
複製代碼
上面的代碼會報錯,由於JavaScript引擎會將{x}理解成一個代碼塊,從而發生預發錯誤。 只要不把{}寫在首行,就會解決這個問題。
let {x} = {x:1};
//或者
let x;
({x} = {x:1})
//也能夠
{(x) = {x:1}}
複製代碼
關於圓括號的使用,保證一個原則,不瞎用。 具體請參考阮一峯大神的es6標準,很全面!總結一下就是,
例子
const [a,b,c,d,e] = 'hello'
複製代碼
解構賦值時,若是等號右邊是數值和布爾值,則會先轉爲對象。
let {toString : s} = 123;
s === Number.prototype.toString //true
let {toString : s} = true;
s === Boolean.prototype.toString //true
複製代碼
上面的代碼中,數字和布爾值的包裝對象都有toString屬性,所以變量s都能取到值。 解構賦值的規則是,只要等號右邊的值不是對象或者數組,就先將其轉爲對象,因爲undefined和null沒法轉換爲對象,因此進行解構賦值時會報錯。
//ES5
var t;
t = a;
a = b;
b = t;
//ES6
let x = 1;
let y = 2;
[x, y] = [y, x];
複製代碼
函數只能返回一個值,若是要返回多個值,只能將他們放在數組或者對象中,有了解構賦值,取出這些值就很方便了。
//返回一個數組
function example() {
return [1,2,3,4]
}
let [a,b,c,d] = example();
//若是沒有解構賦值,還得循環遍歷,分別賦值。
//返回一個對象
function example() {
return {
foo: 1,
bar: 2
};
}
let {foo, bar} = example();
複製代碼
解構賦值能夠方便地將一組參數與變量對應起來
//參數是一組有次序的值
function f([x,y,z]) {}
f([1,2,3])
//參數是一組有序的值
function f({x,y,z}) {}
f({x:1,z:2,x:3});
複製代碼
let jsonData = {
id:23,
state:"draft",
data:{
name:"hansheng",
age: 18
}
}
let {id,state,data:info} = jsonData;
// 23,"draft", {name:"hansheng",age: 18}
複製代碼
本文摘錄自阮一峯ES6標準入門。