ES6系列之解構賦值

數組解構賦值

let [a, b, c] = [1, 2, 3];
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

不徹底解構數組

let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
若是等號的右邊不是數組(嚴格地說,不是可遍歷的結構),那麼將會報錯。

默認值

解構賦值容許指定默認值。函數

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

let [x = 1, y = x] = [];     // x=1; y=1
let [x = y, y = 1] = [];     // ReferenceError: y is not defined
ES6 內部使用嚴格相等運算符(===),判斷一個位置是否有值

若是默認值是一個表達式,那麼這個表達式是惰性求值的,即只有在用到的時候,纔會求值。prototype

function f() {
  console.log('aaa');
}

let [x = f()] = [1];    ///由於x能取到值,因此函數f根本不會執行

對象解構賦值

對象的解構與數組有一個重要的不一樣。數組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。code

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined

//若是變量名與屬性名不一致,必須寫成下面這樣
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
first // undefined

若是要將一個已經聲明的變量用於解構賦值,必須很是當心。對象

// 錯誤的寫法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

// 正確的寫法
let x;
({x} = {x: 1});

因爲數組本質是特殊的對象,所以能夠對數組進行對象屬性的解構。繼承

let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
因爲解構賦值要求等號右邊是一個對象,因此若是等號右邊是undefined或null,就會報錯,由於它們沒法轉爲對象。
let { x, y, ...z } = null; // 運行時錯誤
let { x, y, ...z } = undefined; // 運行時錯誤
解構賦值必須是最後一個參數,不然會報錯。
let { ...x, y, z } = obj; // 句法錯誤
let { x, ...y, ...z } = obj; // 句法錯誤
解構賦值的拷貝是淺拷貝,即若是一個鍵的值是複合類型的值(數組、對象、函數),那麼解構賦值拷貝的是這個值的引用,而不是這個值的副本。
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2
擴展運算符的解構賦值,不能複製繼承自原型對象的屬性。
let o1 = { a: 1 };
let o2 = { b: 2 };
o2.__proto__ = o1;
let { ...o3 } = o2;
o3 // { b: 2 }
o3.a // undefined
若是使用解構賦值,擴展運算符後面必須是一個變量名,而不能是一個解構賦值表達式。
let { x, ...{ y, z } } = o;    // SyntaxError

字符串解構賦值

字符串也能夠解構賦值。這是由於此時,字符串被轉換成了一個相似數組的對象。字符串

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

let {length : len} = 'hello';
len // 5

數值和布爾值解構賦值

解構賦值的規則是,只要等號右邊的值不是對象或數組,就先將其轉爲對象。原型

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

函數參數解構賦值

function add([x, y]){
  return x + y;
}

add([1, 2]); // 3

函數add的參數表面上是一個數組,但在傳入參數的那一刻,數組參數就被解構成變量x和y。io

//默認值
function move({x = 0, y = 0} = {}) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
相關文章
相關標籤/搜索