一、陣列的結構賦值

1>、什麼是解構?

ES6允許我們隊陣列和物件中提取值,對變數進行賦值,這被叫做“解構”。 通常我們像下面這樣為變數賦值:

var a = 1;
    b = 2;
    c = 3;

但是,ES6允許我們像下面這樣做:

var [a, b, c] = [1, 2, 3];

即從陣列中提取值,按照位置的對應關係,對變數賦值。

2>、巢狀陣列解構

再來看看巢狀陣列解構的例子:

var [foo, [[bar], baz]] = [1, [[2], 3]];
foo //1
bar //2
baz //3


var [,, third] = ['foo', 'bar', 'baz'];
third // 'baz'


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

3>、解構不成功、解構失敗

如果解構不成功,變數的值就等於undefined。以下幾種情況均屬於解構不成功:

// 以下均解構不成功
var [foo] = [];
var [foo] = 1;
var [foo] = "Hello";
var [foo] = false;
var [foo] = NaN;

還要,當對undefined和null解構時,就會報錯。

// 報錯
var [foo] = undefined;
var [foo] = null;

為什麼會報錯呢?因為解構只能用於陣列和物件,其它原始型別的值都可以轉為相應的物件。但是,undefined和null不能轉為物件,因此會報錯。

4>、解構賦值允許指定預設值

var [foo = true] = [];
foo //true

5>、解構還適用於let和const命令

var [v1, v2, ...., vN] = array;
let [v1, v2, ...., vN] = array;
const [v1, v2, ...., vN] = array;

二、物件的解構賦值

var {foo, bar} = {
    foo: "aaa",
    bar: "bbb"
};

foo //"aaa"
bar //"bbb"

和陣列解構不同,物件解構時,物件的屬性沒有順序,變數必須與屬性同名才能取得正確的值。

var {bar, foo} = {
    foo: "aaa",
    bar: "bbb"
};

foo //"aaa"
bar //"bbb"


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

1>、巢狀解構的物件

var o = {
    p: [
        "Hello",
        { y: "World" }
    ]
};

var { p: [x, { y }] } = o;
x //"Hello"
y //"world"

2>、指定預設值的物件解構

var { x = 3 } = {};
x //3

3>、特別注意

// 錯誤寫法
var x;
{ x } = {x : 1};
// SyntaxError: Syntax error

報錯的原因是,JS引擎會將{x}理解成一個程式碼塊,從而發生語法錯誤。解決的辦法也很簡單,只要不講大括號寫在行首,避免JS將其解釋為程式碼塊就行了。例如,像下面這樣:

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

// 或者
({x} = {x:1});

三、用途

變數的結構賦值用途很多。

1>、交換變數的值

[x, y] = [y, x];

2>、從函式中返回多個值

函式只能由一個返回值,如果要返回多個返回值,只能將它們放在陣列或物件裡返回。但,有了解析解構,取出這些值就變得非常方便了。看看下面的程式碼示例:

// 返回一個數組
function example() {
    return [1, 2, 3];
}

var [a, b, c] = example();

// 返回一個物件
function example() {
    return {
        foo: 1,
        bar: 2
    };
}

var {foo, bar} = example();

3>、函式引數的定義

function ({s, y, z}) {
    // ..........
}

f({x: 1, y:2, z:3});

這種寫法對提取JSON物件中的資料,尤其重要。

4>、函式引數的預設值

jQuery.ajax = function (url, {
    async = true,
    beforeSend = function() {},
    cache = true,
    complete = function() {},
    crossDomain = false,
    global = true,
    // ....其它設定
}) {
    // ... do stuff
};

通過指定引數的預設值,可以避免在函式體內寫var foo = config.foo || ‘default foo’;這樣的語句。

5>、遍歷Map結構

任何部署了Iterator介面的物件,都可以用for…of迴圈遍歷。Map結構原生支援Iterator介面,配合變數的結構賦值,獲取鍵名和鍵值就變得很方便了。

var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for(let [key, value] of map) {
    console.log(key + "is" + value);
}

// first is hello
// second id world

只獲取鍵名,或者只獲取鍵值。

// 只獲取鍵名
for(let [key] of map) {
    // ......
}

// 只獲取鍵值
for(let [, value] of map) {
    // ......
}

6>、輸入模組的指定方法

在載入模組時,往往需要指定輸入哪些方法。解構賦值使得輸入語句非常清晰。

const {SourceMapConsumer, SourceNode} = require("source-map");