一、什麼是解構賦值
ES6中,通過解構賦值,可以將屬性 / 值從對象 / 數組中取出,賦值給其他變量的操作就是解構賦值。
在下圖上可以發現左側和右側都必須是數組,左側可以定義 n 個變量,那麼與之對應的右側也需要有相應個數的變量值,我們左側的變量從右側取值的操作就是解構賦值。
二、數組解構
在上面的圖示裏可以看出來,數組解構就是從數組中提取值,只要等號兩邊的模式相同,左邊的變量就會在右側的數組裏查找對應位置的值進行賦值操作。
數組結構的應用主要有:
-
對一維數組解構
-
對多維數組解構
-
對字符串解構
-
對...擴展運算符解構
1. 一維數組解構
傳統的變量賦值是這樣的:
let arr = [1,2,3];//把數組的值分別賦給下面的變量;
let a = arr[0];
let b = arr[1];
let c = arr[2];
console.log(a); // a的值爲1
console.log(b); // b的值爲2
console.log(c); // c的值爲3
變量的解構賦值:
let [a,b,c] = [1,2,3]; //把數組的值分別賦給下面的變量;
console.log(a); // a的值爲1
console.log(b); // b的值爲2
console.log(c); // c的值爲3
左側是數組,右側也是數組。
左側的變量會根據索引,依次獲取右側數組裏的值。
代碼短了很多,可讀性也很強,這種叫做數組的解構賦值。
一句話:按索引取值~!
-
不完全解構
當左邊的模式(你可以理解爲格式)與右邊不完全一樣的時候,那麼賦值過程中,只會給模式匹配成功的部分的變量賦值。
-
沒得到的值的變量,返回的就是 undefined。相當於只聲明瞭變量,但是沒賦值。
-
沒有變量存儲的值,就會被浪費掉。
-
let [a] = []; // a = undefined
let [name,age,add] = ["Lily", , "Chongqing"];
console.info( name ); // Lily
console.info( age ); // undefined
console.info( add ); // Chongqing
let [x, , z] = [1, 2, 3]; //x=1,z=3
// 傳統寫法
let arr = [1, 2, 3];
let x = arr[0];
let z = arr[2];
- 左側變量可以設定默認值
如果變量的值取到了 undefined ,那麼左側變量返回的就是默認值。否則,就是右側設定的值。
let [name="Lily",age=18] = [ "Mouse", 20 ] ; // age = 20
let [name="Lily",age=18] = [ "Mouse", 0 ] ; // age = 0
let [name="Lily",age=18] = [ "Mouse", NaN ] ; // age = NaN
let [name="Lily",age=18] = [ "Mouse", null ] ; // age = null
let [name="Lily",age=18] = [ "Mouse" ] ; // age = 18
let [name="Lily",age=18] = [ "Mouse" , undefined ] ; // age = 18
- 可以用來交換變量數據
let a = 1;
let b = 2;
[a,b] = [b,a];
console.info(a,b); // 2 1
2. 多維數組結構
let arr1 = [1,[2,3],4];
let [a1, [b1,c1,d1], e1] = arr1;
console.info( a1,b1,c1,d1,e1); // 1,2,3,undefined,4
按照索引對應就行。
如果兩側不一致:
let [a,b,c] = [1,[2,3]];
console.log(a,b,c); // 1 [2, 3] undefined
從這裏可以看出,結構賦值其實就是一種模式匹配,兩邊模式要一致纔行。
3. 字符串解構
字符串也可以這麼玩,因爲字符串的字符也是有索引的。在解構賦值的過程中,字符串被轉換成了一個類似數組的對象。
// 證明字符串有索引
let str = "hello";
console.info( str[0] ); // h
console.info( str[1] ); // e
// 字符串解構
let str = "hello";
let [a,b, , ,c] = str ;
console.info( a,b,c); // h e o
4. 拓展運算符(...)
也稱爲擴展運算符 ,就是三個連續的點(...)。
作用:取出參數對象中可遍歷的屬性,拷貝到當前對象之中。(百度出來的)
我的個人理解是:可以把數組轉爲數據序列。
-
函數參數
function add(x, y) { // 參數 x,y 是個數據序列,逗號隔開。
return x + y;
}
let numbers = [4, 10]; // 數組
add(...numbers); // 14。 把數組轉爲數據序列,可以作爲函數的參數。
- 複製數組
// 複製數組
let arr1 = [1, 2];
let arr2 = arr1; // 數組是引用數據類型。arr1,arr2 都指向同一個數組空間。
// 一個數據改了,另一個數據也改了
arr2[0] = 2;
console.info(arr1) // [2, 2] ,複製失敗
// 用 ... 拓展運算符就可以複製數組
let arr1 = [1, 2];
let arr2 = [...arr1];
arr2[0] = 2 ;
console.info( arr1 ); // [1, 2] ,複製成功。arr1 不受 arr2 數據變化影響。
- 數組合並
// 傳統做法
let arr = [1,2,3];
let newarr = [4, 5].concat(arr); // 用concat連接兩個數組,返回一個新的數組副本
// ES6 拓展運算符
let arr = [1,2,3];
let newArr1 = [4, 5,...arr];
let newArr2 = [4, ...arr , 5];
console.info( newArr1 ); // [4, 5, 1, 2, 3]
console.info( newArr2 ); // [4, 1, 2, 3, 5]
- 與數組結構一起用
用於生成數組
let [first, ...rest] = [1, 2, 3, 4, 5];
console.info( first ); // 1
console.info( rest ); // [2, 3, 4, 5]
如果將擴展運算符用於數組賦值,只能放在參數的最後一位,否則會報錯。
let [...rest, last] = [1, 2, 3, 4, 5];
// 報錯
let [first, ...rest, last] = [1, 2, 3, 4, 5];
// 報錯
- 將字符串轉爲真正的數組
let str = "hello";
let arr = [...str];
console.info( arr ); // ["h", "e", "l", "l", "o"]
三、對象解構
按照屬性來進行解構賦值,如果解構不成功,變量的值等於 undefined。對象解構可以指定默認值。
1. 和數組解構的對比
-
數組的元素是按次序排列的,變量的取值由它的位置決定;
-
模式匹配,兩邊都必須是 Object 對象。
-
而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。
// 對象的解構賦值,跟順序沒有關係
let {age, name } = { name:"Tom", age:18 };
console.info(age,name); // 18 , Tom
let { age:b, name:a } = { nam e:"Tom", age:18 };
console.info( b, a ); // 18 , Tom
左右屬性名不一致,會得到 undefined。
let {age, nameZ } = { name:"Tom", age:18 };
console.info(age,nameZ); // 18 , undefined
let { age:b, nameZ:a } = { name:"Tom", age:18 };
console.info( b, a ); // 18 , undefined
對象解構語句不是以變量聲明關鍵字(如var,let或const)開頭,則需要將語句包裹在括號中。 否則會報錯。
({ a, b } = { a:100, b:200 } ); // good
let { a, b } = { a:100, b:200 } ; // good
let a , b ;
{ a, b } = { a:100, b:200 } ; // 報錯
2. 對象解構默認值
// 變量的非 undefined 的值可以取到
let { name, age = 28 } = { name:"Tom", age:18 };
console.info( name, age ); // Tom , 18
// 變量取到了 undefined ,則返回默認值
let { name, age = 28 } = { name:"Tom" };
console.info( name, age ); // Tom , 28
let {name: a = "Tom", age: b = 28} = { name :"Lily"};
console.info( a, b ); // Lily, 28
// 右側一個值都沒有
let {name: a = "Tom", age: b = 28} = {};
console.info( a, b ); // Tom, 28
3. 對象作爲函數參數
Object 對象可以作爲函數參數。
let addFun = function( obj ){
let sum = obj.a + obj.b ;
console.info( sum );
};
addFun({
a:100,
b:200
}); // 300
爲了設置 a ,b 默認值。利用對象解構,設置形參:
// 實參和形參會進行解構操作。
let addFun = function( { a=100, b=100 } ){
let sum = a + b ;
console.info( sum );
};
addFun({
a:100,
b:200
}); // 300。a ,100 ; b,200
addFun({ a:50 }); // 150。a,50; b 被省略,取默認值 100 。
addFun({ }); // 200。a , b 均取默認值
addFun(); // Cannot read property 'a' of undefined
上面代碼只使用了對象的解構賦值默認值,沒有使用函數參數的默認值。只有當函數 addFun 的參數是一個對象時,變量 a 和 b 纔會通過解構賦值生成。
如果函數 addFun 調用時沒提供參數,變量 a 和 b 就不會生成,從而報錯。
addFun(); // 報錯。Uncaught TypeError: Cannot read property 'a' of undefined
相當於在執行代碼
{ a=100, b=100 } = undefined ;
試圖對 undefined 進行對象結構,會報錯。
通過提供函數參數的默認值,就可以避免這種情況。
let addFun = function( { a=100, b=100 } = {} ){
let sum = a + b ;
console.info( sum );
};
addFun( ); // 200。
參數默認值是 {} 。{} 會解構給 a,b 賦值。a,b 解構的值都是 undefined,所以取 a,b 均會獲取解構的默認值 100。
四、對非對象進行解構
如果解構的值爲 null、undefined,會得到一個類型錯誤提示。
如果你的值爲數字、布爾值、字符串,會得到一個 undefined。
如果等號左側的變量名爲 Object.prototype 上的方法名稱時,返回的就是方法實例。
let {a} = null ; // 報錯
let {a} = undefined ; // 報錯
let { age:a } = undefined ; // 報錯
let {a} = 13 ; // a = undefined
let { toString } = 123 ; // toString() { [native code] }