解構賦值

解構賦值是一種 JavaScript 運算式,可以將陣列或物件中的資料取出成獨立變數。

語法

var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({a, b} = {a: 10, b: 20});
console.log(a); // 10
console.log(b); // 20

// 實驗性(尚未標準化)
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}); 

說明

這種物件或陣列的運算式提供一個簡單的方式來建立特定的資料組。

var x = [1, 2, 3, 4, 5];

解構指派式使用類似的語法,但在指派式的左邊是被指派的元素,右邊則指定來源。

var x = [1, 2, 3, 4, 5];
var [y, z] = x;
console.log(y); // 1
console.log(z); // 2

這類似於 Perl 和 Python。

陣列解構

基本變數指派

var foo = ["one", "two", "three"];

var [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"

從宣告解構指派

變數可以透過解構指派式個別指派。

var a, b;

[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2

預設值

變數可以被設定預設值,當在陣列對應的元素是 undefined 時會被使用。

var a, b;

[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7

變數交換

兩個變數可以透過一個解構指派式交換。

沒有解構指派式時,這需要一個暫存變數來達成(或者某些低階語言像是 XOR-swap trick)。

var a = 1;
var b = 3;

[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1

解析自函式回傳的陣列

一直以來函式都可以回傳陣列,而解構指派式可以讓回傳的值更為簡潔。

在這個例子, f() 回傳 [1, 2] ,接著透過一個解構指派式解析。

function f() {
  return [1, 2];
}

var a, b; 
[a, b] = f(); 
console.log(a); // 1
console.log(b); // 2

忽略某些回傳值

你可以忽略某些回傳值:

function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
console.log(a); // 1
console.log(b); // 3

當然你也可以全部忽略:

[,,] = f();

將剩餘部分解構到一個變數

解構一個陣列時,你可以透過展開運算子將剩餘的部分指派到一個變數:

var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]

Note that a SyntaxError will be thrown if a trailing comma is used on the left-hand side with a rest element:

var [a, ...b,] = [1, 2, 3];
// SyntaxError: rest element may not have a trailing comma

從正則運算式的比對結果取值

當正則運算式的方法 exec() 比對到一個值,回傳的一個陣列中第一個值是符合整個運算式的字串,其他的則是比對到括號的部分。解構指派式讓你更簡單的取出這部分,並可以忽略第一個。

var url = 'https://developer.mozilla.org/en-US/Web/JavaScript';

var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]

var [, protocol, fullhost, fullpath] = parsedURL;

console.log(protocol); // "https"

物件解構

基本指派

var o = {p: 42, q: true};
var {p, q} = o;

console.log(p); // 42
console.log(q); // true 

無宣告指派

變數可以透過解構指派式個別指派。

var a, b;

({a, b} = {a:1, b:2});

使用子物件表示法解構時,在指派語法外的括號——( .. )——是必要的。
* 子物件表示法原文 object literal,指以逗號分隔屬性的表示方式。

{a, b} = {a: 1, b: 2} 不是有效的獨立語法,因為左邊的 {a, b} 被視為一個(程式碼)區塊而非物件。

然而 ({a, b} = {a: 1, b: 2}) 有效,如同 var {a, b} = {a: 1, b: 2}

NOTE: Your ( ..) expression needs to be preceded by a semi-colon or it may be used to execute a function on the previous line.

指派到新的變數

變數可以從物件中提出到另一個不同名稱的變數。

var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
 
console.log(foo); // 42 
console.log(bar); // true  

預設值

變數可以設定預設值,當物件中對應的值是 undefined 時使用。

var {a=10, b=5} = {a: 3};

console.log(a); // 3
console.log(b); // 5

設定函式的預設值

ES5 版本

function drawES5Chart(options) {
  options = options === undefined ? {} : options;
  var size = options.size === undefined ? 'big' : options.size;
  var cords = options.cords === undefined ? {x: 0, y: 0} : options.cords;
  var radius = options.radius === undefined ? 25 : options.radius;
  console.log(size, cords, radius);
  // 終於畫了東西
}

drawES5Chart({
  cords: {x: 18, y: 30},
  radius: 30
});

ES2015 version

function drawES2015Chart({size = 'big', cords = {x: 0, y: 0}, radius = 25} = {}) {
  console.log(size, cords, radius);
  // 這樣就畫了東西
}

drawES2015Chart({
  cords: {x: 18, y: 30},
  radius: 30
});

巢狀物件或陣列的解構

var metadata = {
    title: 'Scratchpad',
    translations: [
       {
        locale: 'de',
        localization_tags: [],
        last_edit: '2014-04-14T08:43:37',
        url: '/de/docs/Tools/Scratchpad',
        title: 'JavaScript-Umgebung'
       }
    ],
    url: '/en-US/docs/Tools/Scratchpad'
};

var {title: englishTitle, translations: [{title: localeTitle}]} = metadata;

console.log(englishTitle); // "Scratchpad"
console.log(localeTitle);  // "JavaScript-Umgebung"

循環取出的解構

var people = [
  {
    name: 'Mike Smith',
    family: {
      mother: 'Jane Smith',
      father: 'Harry Smith',
      sister: 'Samantha Smith'
    },
    age: 35
  },
  {
    name: 'Tom Jones',
    family: {
      mother: 'Norah Jones',
      father: 'Richard Jones',
      brother: 'Howard Jones'
    },
    age: 25
  }
];

for (var {name: n, family: {father: f}} of people) {
  console.log('Name: ' + n + ', Father: ' + f);
}

// "Name: Mike Smith, Father: Harry Smith"
// "Name: Tom Jones, Father: Richard Jones"

從做為函式參數的物件中提出某屬性的值

function userId({id}) {
  return id;
}

function whois({displayName, fullName: {firstName: name}}) {
  console.log(displayName + ' is ' + name);
}

var user = { 
  id: 42, 
  displayName: 'jdoe',
  fullName: { 
      firstName: 'John',
      lastName: 'Doe'
  }
};

console.log('userId: ' + userId(user)); // "userId: 42"
whois(user); // "jdoe is John"

這樣從 user 物件中提出了 id, displayNamefirstName 並且印出。

以物件演算屬性名稱解構

物件演算屬性名稱(像是在 object literals)可以在解構指派式使用。
(物件演算屬性名稱指——母物件["子物件名稱"]——的表示方式)

let key = 'z';
let {[key]: foo} = {z: 'bar'};

console.log(foo); // "bar"

規範

規範 狀態 標記
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Destructuring assignment' in that specification.
Standard 初定義
ECMAScript Latest Draft (ECMA-262)
The definition of 'Destructuring assignment' in that specification.
Draft

瀏覽器相容性

特性 Chrome Firefox (Gecko) Edge Internet Explorer Opera Safari
基本支援 49.0 2.0 (1.8.1) 14 No support (Yes) 7.1
物件演算屬性名稱 49.0 34 (34) 14 No support (Yes) No support
展開運算子 49.0 34 (34) 12[1] ? ? ?
特性 Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
基本支援 No support 49.0 1.0 (1.0) No support No support 8 49.0
物件演算屬性名稱 No support 49.0 34.0 (34) No support No support No support 49.0
展開運算子 No support 49.0 34.0 (34) ? ? ? 49.0

[1] 需要在 `about:flags` 中啟動 "Enable experimental Javascript features"。

在 Firefox 上

  • Firefox 提供使用 JS1.7 的非標準語言擴充插件來支援分離指派式。這個插件在 Gecko 40 (Firefox 40 / Thunderbird 40 / SeaMonkey 2.37) 已被移除,請見 bug 1083498
  • 自 Gecko 41 (Firefox 41 / Thunderbird 41 / SeaMonkey 2.38) 開始為了遵守 ES2015 規範,括弧內的分離指派式如 ([a, b]) = [1, 2]({a, b}) = { a: 1, b: 2 }被視為無效並且會出現 SyntaxError。更多資訊請見 Jeff Walden's blog postbug 1146136

參見

文件標籤與貢獻者

 此頁面的貢獻者: jackblackevo, pa-da
 最近更新: jackblackevo,