解析JavaScript的ES6版本中的解構賦值
什么是解構賦值?
解構賦值允許你使用類似數(shù)組或對象字面量的語法將數(shù)組和對象的屬性值賦給一系列變量。這個語法非常簡潔,而且比傳統(tǒng)的屬性訪問更加清晰。
在不使用解構賦值的情況下,訪問數(shù)組的前三項:
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 引擎)已經(jīng)支持解構賦值的大部分特性,但還不完全。
數(shù)組和可迭代對象的解構賦值
上面我們已經(jīng)看到了數(shù)組解構賦值的例子,該語法的一般形式是:
[ variable1, variable2, ..., variableN ] = array; [ variable1, variable2, ..., variableN ] = array;
這將把數(shù)組中對應的項依次賦給 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); // 1 console.log(bar); // 2 console.log(baz); // 3 var [foo, [[bar], baz]] = [1, [[2], 3]]; console.log(foo); // 1 console.log(bar); // 2 console.log(baz); // 3
此外,還可以跳過數(shù)組中的某些項:
var [,,third] = ["foo", "bar", "baz"]; console.log(third); // "baz" var [,,third] = ["foo", "bar", "baz"]; console.log(third); // "baz"
你還可以用一個 Rest 表達式來捕獲數(shù)組中的剩余項:
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]
如果數(shù)組越界或訪問數(shù)組中不存在的項,將得到和通過數(shù)組索引訪問一樣的值:undefined。
console.log([][0]); // undefined var [missing] = []; console.log(missing); // undefined console.log([][0]); // undefined var [missing] = []; console.log(missing); // undefined
注意,數(shù)組解構賦值的方式也同樣適用于可遍歷的對象:
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"
與數(shù)組一樣,也可以嵌套:
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 外,其它類型都可以被強制轉換為對象。進行數(shù)組的結構賦值時,要求被解構的對象有一個遍歷器。
默認值
可以為不存在的屬性指定一個默認值:
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
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
實際應用
函數(shù)參數(shù)
作為開發(fā)人員,我們經(jīng)常把一個包含多個屬性的對象作為函數(shù)的參數(shù),來實現(xiàn)更靈活的 API,而不是讓 API 的使用者記住一些特定順序的參數(shù)。我們可以使用對象的解構賦值,來避免每次使用參數(shù)時的屬性訪問:
function removeBreakpoint({ url, line, column }) {
// ...
}
function removeBreakpoint({ url, line, column }) {
// ...
}
配置對象
完善上面的例子,我們可以為要被解構的對象屬性提供默認值,這在對那些作為配置參數(shù)的對象非常實用,因為許多配置項都有一個合理的默認值。例如,jQuery 的 ajax 方法的第二個參數(shù)為一個配置對象,我們可以這樣實現(xiàn):
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) {
// ...
}
返回多個值
返回一個數(shù)組,通過解構賦值提取到返回值:
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;
采用延續(xù)式:
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,我們已經(jīng)有很多經(jīng)驗。Lars Hansen 在 10 年前就向 Opera 引入了解構賦值,Brendan Eich 在稍微晚點也給 Firefox 添加了支持,最早出現(xiàn)在 Firefox 2 中。因此,解構賦值已經(jīng)滲透到我們每天對 JS 的使用中,悄悄地使我們的代碼更簡短、整潔。
相關文章
網(wǎng)絡傳輸協(xié)議(http協(xié)議)
網(wǎng)絡傳輸協(xié)議(http協(xié)議)指服務器和客戶端間進行通信時的約束和規(guī)范,客戶端與服務端的數(shù)據(jù)交互并不是雜亂無章的,需要遵照(基于)一定的規(guī)范進行,本文主要介紹http超文本傳輸協(xié)議。希望對大家有所幫助2016-11-11
JavaScript中document.referrer的用法詳解
這篇文章主要給大家介紹了關于JavaScript中document.referrer的用法,文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。2017-07-07
JavaScript入門教程(9) Document文檔對象
Document文檔對象是JavaScript中window和frames對象的一個屬性,是顯示于窗口或框架內的一個文檔。2009-01-01
Javascript學習筆記之函數(shù)篇(六) : 作用域與命名空間
本文主要講述了javascript中作用域和命名空間的區(qū)別,十分的詳細,這里推薦給大家,希望小伙伴能有所收獲2014-11-11

