解析JavaScript的ES6版本中的解構賦值_基礎知識

來源:互聯網
上載者:User

什麼是解構賦值?

解構賦值允許你使用類似數組或對象字面量的文法將數組和對象的屬性值賦給一系列變數。這個文法非常簡潔,而且比傳統的屬性訪問更加清晰。

在不使用解構賦值的情況下,訪問數組的前三項:

var first = someArray[0];var second = someArray[1];var third = someArray[2]; var first = someArray[0];var second = someArray[1];var third = someArray[2];

使用解構賦值後,相應的代碼變得更簡潔和可讀:

var [first, second, third] = someArray; var [first, second, third] = someArray;

SpiderMonkey(Firefox 的 JavaScript 引擎)已經支援解構賦值的大部分特性,但還不完全。
數組和可迭代對象的解構賦值

上面我們已經看到了數組解構賦值的例子,該文法的一般形式是:

[ variable1, variable2, ..., variableN ] = array; [ variable1, variable2, ..., variableN ] = array;

這將把數組中對應的項依次賦給 variable1 到 variableN,如果同時需要聲明變數,可以在解構運算式前面添加 var,let 或 const 關鍵字。

var [ variable1, variable2, ..., variableN ] = array;let [ variable1, variable2, ..., variableN ] = array;const [ variable1, variable2, ..., variableN ] = array; var [ variable1, variable2, ..., variableN ] = array;let [ variable1, variable2, ..., variableN ] = array;const [ variable1, variable2, ..., variableN ] = array;

事實上,你還可以嵌套任意的深度:

var [foo, [[bar], baz]] = [1, [[2], 3]];console.log(foo);// 1console.log(bar);// 2console.log(baz);// 3 var [foo, [[bar], baz]] = [1, [[2], 3]];console.log(foo);// 1console.log(bar);// 2console.log(baz);// 3

此外,還可以跳過數組中的某些項:

var [,,third] = ["foo", "bar", "baz"];console.log(third);// "baz" var [,,third] = ["foo", "bar", "baz"];console.log(third);// "baz"

你還可以用一個 Rest 運算式來捕獲數組中的剩餘項:

var [head, ...tail] = [1, 2, 3, 4];console.log(tail);// [2, 3, 4] var [head, ...tail] = [1, 2, 3, 4];console.log(tail);// [2, 3, 4]

如果數組越界或訪問數組中不存在的項,將得到和通過數組索引訪問一樣的值:undefined。

console.log([][0]);// undefinedvar [missing] = [];console.log(missing);// undefined console.log([][0]);// undefined var [missing] = [];console.log(missing);// undefined

注意,數組解構賦值的方式也同樣適用於可遍曆的對象:

function* fibs() { var a = 0; var b = 1; while (true) {  yield a;  [a, b] = [b, a + b]; }}var [first, second, third, fourth, fifth, sixth] = fibs();console.log(sixth);// 5 function* fibs() { var a = 0; var b = 1; while (true) {  yield a;  [a, b] = [b, a + b]; }} var [first, second, third, fourth, fifth, sixth] = fibs();console.log(sixth);// 5

對象的解構賦值

對象的解構賦值允許你將變數綁定到對象不同的屬性值。指定被綁定的屬性名稱,後面緊跟要綁定的變數:

var robotA = { name: "Bender" };var robotB = { name: "Flexo" };var { name: nameA } = robotA;var { name: nameB } = robotB;console.log(nameA);// "Bender"console.log(nameB);// "Flexo" var robotA = { name: "Bender" };var robotB = { name: "Flexo" }; var { name: nameA } = robotA;var { name: nameB } = robotB; console.log(nameA);// "Bender"console.log(nameB);// "Flexo"

當綁定的屬性名稱和接收屬性值的變數名一樣時,還有一個文法糖:

var { foo, bar } = { foo: "lorem", bar: "ipsum" };console.log(foo);// "lorem"console.log(bar);// "ipsum" var { foo, bar } = { foo: "lorem", bar: "ipsum" };console.log(foo);// "lorem"console.log(bar);// "ipsum"

與數組一樣,也可以嵌套:

var complicatedObj = { arrayProp: [  "Zapp",  { second: "Brannigan" } ]};var { arrayProp: [first, { second }] } = complicatedObj;console.log(first);// "Zapp"console.log(second);// "Brannigan" var complicatedObj = { arrayProp: [  "Zapp",  { second: "Brannigan" } ]}; var { arrayProp: [first, { second }] } = complicatedObj; console.log(first);// "Zapp"console.log(second);// "Brannigan"

解構一個不存在的屬性時,將得到 undefined:

var { missing } = {};console.log(missing);// undefined var { missing } = {};console.log(missing);// undefined

使用對象的解構賦值時還有一個潛在的陷阱,在解構賦值時沒有聲明變數(沒有 var、let或 const 關鍵字):

{ blowUp } = { blowUp: 10 };// Syntax error { blowUp } = { blowUp: 10 };// Syntax error

這是因為 JavaScript 文法告訴引擎任何以 { 開始的語句都是語句塊(例如,{console} 就是一個合法的語句塊),解決方案是將整個語句用一對括弧包裹:

({ safe } = {});// No errors ({ safe } = {});// No errors

其他情況

當你嘗試解構 null 或 undefined,你將得到類型錯誤:

var {blowUp} = null;// TypeError: null has no properties var {blowUp} = null;// TypeError: null has no properties

不過,你可以對其他基本類型(Boolean、String 和 Number)進行解構,將得到 undefined:

var {wtf} = NaN;console.log(wtf);// undefined var {wtf} = NaN;console.log(wtf);// undefined

結果也許會讓你感到意外,但深究一下,其實原因很簡單。在進行對象解構賦值時,被解構的對象將被強制轉換為 Object,除 null 和 undefined 外,其它類型都可以被強制轉換為對象。進行數組的結構賦值時,要求被解構的對象有一個遍曆器。
預設值

可以為不存在的屬性指定一個預設值:

var [missing = true] = [];console.log(missing);// truevar { message: msg = "Something went wrong" } = {};console.log(msg);// "Something went wrong"var { x = 3 } = {};console.log(x);// 3 var [missing = true] = [];console.log(missing);// true var { message: msg = "Something went wrong" } = {};console.log(msg);// "Something went wrong" var { x = 3 } = {};console.log(x);// 3

實際應用
函數參數

作為開發人員,我們經常把一個包含多個屬性的對象作為函數的參數,來實現更靈活的 API,而不是讓 API 的使用者記住一些特定順序的參數。我們可以使用對象的解構賦值,來避免每次使用參數時的屬性訪問:

function removeBreakpoint({ url, line, column }) { // ...} function removeBreakpoint({ url, line, column }) { // ...}

設定物件

完善上面的例子,我們可以為要被解構的對象屬性提供預設值,這在對那些作為配置參數的對象非常實用,因為許多配置項都有一個合理的預設值。例如,jQuery 的 ajax 方法的第二個參數為一個設定物件,我們可以這樣實現:

jQuery.ajax = function (url, { async = true, beforeSend = noop, cache = true, complete = noop, crossDomain = false, global = true, // ... more config}) { // ... do stuff}; jQuery.ajax = function (url, { async = true, beforeSend = noop, cache = true, complete = noop, crossDomain = false, global = true, // ... more config}) { // ... do stuff};

這避免了類似這樣的重複代碼:var foo = config.foo || theDefaultFoo;。
與迭代器一起使用

當遍曆 Map 對象時,我們可以使用解構賦值來遍曆 [key, value]:

var map = new Map();map.set(window, "the global");map.set(document, "the document");for (var [key, value] of map) { console.log(key + " is " + value);}// "[object Window] is the global"// "[object HTMLDocument] is the document" var map = new Map();map.set(window, "the global");map.set(document, "the document"); for (var [key, value] of map) { console.log(key + " is " + value);}// "[object Window] is the global"// "[object HTMLDocument] is the document"

只遍曆鍵:

for (var [key] of map) { // ...} for (var [key] of map) { // ...}只遍曆值:for (var [,value] of map) { // ...} for (var [,value] of map) { // ...}

返回多個值

返回一個數組,通過解構賦值提取到傳回值:

function returnMultipleValues() { return [1, 2];}var [foo, bar] = returnMultipleValues(); function returnMultipleValues() { return [1, 2];}var [foo, bar] = returnMultipleValues();

或者,返回一個索引值對的對象:

function returnMultipleValues() { return {  foo: 1,  bar: 2 };}var { foo, bar } = returnMultipleValues(); function returnMultipleValues() { return {  foo: 1,  bar: 2 };}var { foo, bar } = returnMultipleValues();

這兩者都比使用中間變數好:

function returnMultipleValues() { return {  foo: 1,  bar: 2 };}var temp = returnMultipleValues();var foo = temp.foo;var bar = temp.bar; function returnMultipleValues() { return {  foo: 1,  bar: 2 };}var temp = returnMultipleValues();var foo = temp.foo;var bar = temp.bar;

採用延續式:

function returnMultipleValues(k) { k(1, 2);}returnMultipleValues((foo, bar) => ...); function returnMultipleValues(k) { k(1, 2);}returnMultipleValues((foo, bar) => ...);

匯入 CommonJS 模組的指定部分

還沒使用過 ES6 的模組吧,那至少使用過 CommonJS 吧。當匯入一個 CommonJS 模組 X 時,模組提供的方法也許多餘你實際使用的。使用解構賦值,你可以明確指定你需要使用模組的哪些部分:

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

如果你使用 ES6 的模組機制,你可以看到 import 聲明時有一個類似的文法。
結論

我們看到,解構賦值在很多情境下都很實用。在 Mozilla,我們已經有很多經驗。Lars Hansen 在 10 年前就向 Opera 引入瞭解構賦值,Brendan Eich 在稍微晚點也給 Firefox 添加了支援,最早出現在 Firefox 2 中。因此,解構賦值已經滲透到我們每天對 JS 的使用中,悄悄地使我們的代碼更簡短、整潔。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.