1. 程式人生 > >JS的解構賦值詳解

JS的解構賦值詳解

小熙在學習前端特性的時候,恰好碰到一篇詳細的結構賦值詳解,特此轉載以供分享

解構賦值語法是一個 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 // Stage 3 proposal ({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}); console.log(a); // 10 console.log(b); // 20 console.log(rest); //{c: 30, d: 40}

描述

物件字面量和陣列字面量提供了一種簡單的定義一個特定的資料組的方法。

let 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技巧)。

var a = 1;
var b = 3;

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

解析一個從函式返回的陣列

從一個函式返回一個數組是十分常見的情況.。解構使得處理返回值為陣列時更加方便。

在下面例子中,[1, 2] 作為函式的 f() 的輸出值,可以使用解構用一句話完成解析。

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]

注意:如果剩餘元素右側有一個逗號,會丟擲SyntaxError,因為剩餘元素必須是陣列的最後一個元素。

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

賦值語句周圍的( ... ) 是使用物件字面解構賦值時不需要宣告的語法。{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

預設值

變數可以先賦予預設值。當要提取的物件沒有對應的屬性,變數就被賦予預設值。

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

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

給新的變數命名並提供預設值

一個屬性可以是1)從一個物件解構,並分配給一個不同名稱的變數,2)分配一個預設值,以防未解構的值是undefined

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

console.log(aa); // 3
console.log(bb); // 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);
  // now finally do some chart drawing
}

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

ES2015版本

function drawES2015Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = {}) 
{
  console.log(size, cords, radius);
  // do some chart drawing
}

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

在上面的drawES2015Chart的函式簽名中,解構的左手邊被分配給右手邊的空物件字面值:{size = 'big', cords = {x: 0, y: 0}, radius = 25} = {}。你也可以在沒有右側分配的情況下編寫函式。但是,如果你忽略了右邊的賦值,那麼函式會在被呼叫的時候查詢至少一個被提供的引數,而在當前的形式下,你可以直接呼叫drawES2015Chart()而不提供任何引數。如果你希望能夠在不提供任何引數的情況下呼叫該函式,則當前的設計非常有用,而另一種方法在您確保將物件傳遞給函式時非常有用。

解構巢狀物件和陣列

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"

For of 迭代和解構

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物件中提取並輸出iddisplayNamefirstName

物件屬性計算名和解構

計算屬性名,如object literals,可以被解構。

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

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

物件解構中的Rest

Rest/Spread Properties for ECMAScript 提案(階段3)將rest語法新增到解構中。Rest 屬性收集尚未被解構模式拾取的剩餘可列舉屬性鍵。

let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
a; // 10 
b; // 20 
rest; // { c: 30, d: 40 }

無效的 JavaScript 識別符號作為屬性名稱

通過提供有效的替代識別符號,解構可以與不是有效的JavaScript識別符號的屬性名稱一起使用。

const foo = { 'fizz-buzz': true };
const { 'fizz-buzz': fizzBuzz } = foo;

console.log(fizzBuzz); // "true"

規範

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
Destructuring assignment
Standard Initial definition.
ECMAScript Latest Draft (ECMA-262)
Destructuring assignment
Draft  
Rest/Spread Properties for ECMAScript Draft Stage 3 draft.

瀏覽器相容

The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out  https://github.com/mdn/browser-compat-data and send us a pull request.

Update compatibility data on GitHub
Desktop Mobile Server
Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Edge Mobile Firefox for Android Opera for Android iOS Safari Samsung Internet Node.js
Basic support Chrome Full support 49 Edge Full support 14 Firefox Full support 41 Notes 開啟
Full support 41 Notes
Notes Firefox provided a non-standard destructuring implementation from Firefox 2 to 40.
IE No support No Opera Full support Yes Safari Full support 8 WebView Android Full support 49 Chrome Android Full support 49 Edge Mobile Full support 14 Firefox Android Full support 41 Notes 開啟
Full support 41 Notes
Notes Firefox provided a non-standard destructuring implementation from Firefox 2 to 40.
Opera Android Full support Yes Safari iOS Full support 8 Samsung Internet Android Full support 5.0 nodejs Full support 6.0.0
Computed property names Chrome Full support 49 Edge Full support 14 Firefox Full support 34 IE No support No Opera Full support Yes Safari No support No WebView Android Full support 49 Chrome Android Full support 49 Edge Mobile Full support 14 Firefox Android Full support 34 Opera Android Full support Yes Safari iOS No support No Samsung Internet Android Full support 5.0 nodejs