Destructuring assignment

此文件需要編輯審查。看看您能幫什麼忙。

Destructuring assignment (暫譯:分離指派式)是一種 JavaScript 表達式,可以將陣列或物件中的資料取出成獨立變數。

語法

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

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

({a, b} = {a:1, b:2});
console.log(a); // 1
console.log(b); // 2

// ES7 - 未在 Firefox 47a01 中實現
({a, b, ...rest} = {a:1, b:2, c:3, d:4}); 

表達式

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

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]

從正則表達式的比對結果取值

當正則表達式的方法 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}。

指派到新的變數

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

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
});

ES6 version

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

drawES6Chart({
  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: 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, displayName 和 firstName 並且印出。

以物件演算屬性名稱分離

物件演算屬性名稱(像是在 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 2017 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 No support 7.1
物件演算屬性名稱 49.0 34 (34) 14 No support No support 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) 開始為了遵守 ES6 規範,括弧內的分離指派式如 ([a, b]) = [1, 2]({a, b}) = { a: 1, b: 2 }被視為無效並且會出現 SyntaxError。更多資訊請見 Jeff Walden's blog postbug 1146136

看更多

文件標籤與貢獻者

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