1、數組的解構賦值
基本用法
本質上,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值,...表示將剩下的值賦予此變量,無剩余則賦值為空數組,解構不成功則賦值為undefined。等號兩邊都要為數組。
let a = 1;
let b = 2;
let c = 3;
//ES6可以寫成
let [a, b, c] = [1, 2, 3];
//多重數組的例子
let [a, [[b], c]] = [1, [[2], 3]];
a // 1
b // 2
c // 3
//對應位置賦予對應的值
let [ , , c] = ["1", "2", "3"];
c // "3"
let [a, , c] = [1, 2, 3];
a // 1
c // 3
//...語法有剩余值時
let [a, ...z] = [1, 2, 3, 4];
a // 1
z // [2, 3, 4]
//...語法無剩余值時
let [a, b, ...z] = ['a'];
a // "a"
b // undefined
z // [] 空數組
默認值
解構賦值可以使用默認值,當且僅當變量的值全等于(===)undefined時,才會使用默認值,即使是等于null時也不會使用默認值。
let [a = 1] = []; a // 1
let [a, b = '2'] = ['1']; // a='1', b='2'
let [a, b = '2'] = ['1', undefined]; // a='1', b='2'
let [x = 1] = [null]; x // null
當默認值是一個表達式的時候(例如一個行數表達式),若變量能夠取到值(值不全等于undefined),則表達式不會執行。
function f() {
console.log('a');
}
let [x = f()] = [1]; //f()不會執行,y=1
默認值可以引用解構賦值中的其他變量,前提是變量已經聲明
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // y在x引用的時候還沒有聲明,所以報錯。
2、對象的解構賦值
與數組的解構賦值不同的是,數組解構是按照元素的次序賦值的,而對象則不受次序的影響,變量必須與屬性同名,才能被賦值,沒有同名屬性則賦值為undefined。
let { pro1, pro2 } = { pro1: "1", pro2: "2" };
pro1 // "1"
pro2 // "2"
//上述表述是一種縮寫,其本質是
let { pro1:pro1, pro2:pro2 } = { pro1: "1", pro2: "2" };
//在等號左邊時,:號左邊的pro1和pro2是定義匹配模式,真正被賦值的是:號右邊的pro1和pro2,當匹配模式和屬性名同名時,可以使用縮寫
let { proa:prox, prob:proy } = { proa: "1", prob: "2" };
prox //"1"
proy //"2"
對象解構中左邊的變量一定是由:組成的一對匹配模式和屬性名。只有一個匹配模式時,一定是匹配模式和屬性名相同,使用了簡寫。
var obj= {
a: {
b: {
c: 1,
d: 2
}
}
};
var { a: { b: { c }} } = obj;
a // 報錯,a在:左邊,是匹配模式,不是屬性名
b // 報錯,b在:左邊,是匹配模式,不是屬性名
c // 1
對象的解構賦值同樣支持默認值,規則與數組的解構相似:
- 當且僅當變量值全等于(===)undefined時,才會取默認值。
- 如果解構失敗,變量的值等于undefined。
當大括號位于本行的首位時,需要加上小括號,因為 { } 表示一個代碼塊,不是一個單獨的語句。
let x;
{x} = {x: 1}; // 語法錯誤,左邊是一個代碼塊,不是一個聲明。
({x} = {x: 1}); // 加上小括號,成為一個單獨的語句,語法正確。
當變量名與現有對象的屬性名相同時,可以直接使用對象賦值。
let { log, sin, cos } = Math;
log // Math.log
sin // Math.sin
cos // Math.cos
因為在JavaScript中,數組是特殊的對象,所以可以用數組進行對象屬性的結構。
let arr = [1, 2, 3];
let {0 : a, [arr.length - 1] : b} = arr;
a // 1
b // 3
3、字符串的解構賦值
字符串進行結構賦值時,被轉化為了一個類似數組的對象。
const [a, b, c, d, e] = 'hello';
a // 'h'
let {length : len} = 'hello';
len // 5 因為右邊'hello'字符串被轉化為了一個類似數組的對象,具有length屬性,所以可以直接賦值給左邊同名的匹配模式。
4、數值和布爾值的解構賦值
解構賦值時,如果等號右邊是數值和布爾值,則會先轉為對象。
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
解構賦值的規則是,只要右邊不是對象或者數組,就將其轉化為對象,再進行匹配賦值。
因為undefined和null不能轉化為對象,所以單獨將這兩個值當做右邊的值進行匹配賦值時會報錯。
let { prop: x } = undefined; // 報錯
let { prop: y } = null; // 報錯
5、函數參數的解構賦值
function add([x, y]){
return x + y;
}
add([1,2]); // 傳輸數組參數相當于執行了 [x,y]=[1,2];x和y被分別賦值為1和2
函數參數的解構也可以使用默認值,但下面兩種情況不同:
function move({x = 0, y = 0} = {}) {
return [x, y];
}
這種方式表示x和y沒有給定值時默認值為0,x和y是分開賦值的,只要參數中存在沒有傳入的項,就使用其默認值。
即只要某一項參數不存在,就一定會使用其默認值。
function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
這種方式指定的是整個參數的默認值,而不是單獨指定x和y,x和y是當做一個整體。只有當完全不傳任何參數時,才會使用默認值(傳入空對象也不會使用默認值),無論是單獨傳了x參數,還是單獨傳了y參數,未傳的項都不會使用默認值。
即只要存在參數,且參數不全等于(===)undefined,就一定不會使用默認值。
6、圓括號問題
ES6的規則是:只要有可能導致解構歧義,就不得使用圓括號。
所以,在非必要情況下,沒有必要添加圓括號(事實上大部分圓括號都是沒有必要添加的)。
不允許使用圓括號的情況
- 聲明語句中不允許使用圓括號
- 函數參數中,匹配模式不允許使用圓括號,因為函數參數也屬于變量聲明
- 不能將整個模式或嵌套中的某一整層放在圓括號當中。
7、解構用途
交換變量的值
let x = 1;
let y = 2;
[x, y] = [y, x]; // 簡潔易懂的交換
從函數返回多個值
當函數需要返回多個值時,將這些值組成一個數組或對象,返回這個數組或對象,然后再用解構賦值來取的各項的值。
// 返回一個數組
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 返回一個對象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
函數參數的定義(包括函數參數使用默認值)
// 參數是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 參數是一組無次序的值
function f({x=0, y=0, z=0}) { ... }
f({z: 3, y: 2, x: 1});
提取JSON數據
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]