本文內容主要來自Nicholas C. Zakas的《Understanding ECMAScript 6》。
ES6簡化了從物件和陣列中獲取資料的方法,解構可以把一個資料結構拆分成任意小的部分。我們在開發中經常使用物件和陣列的解構來簡化程式碼,以下幾個很有用但經常被忽略的用法。
Value Swapping
value swapping在排序演算法中經常出現,在ES5中,我們需要第三個臨時變數來完成兩個數值的交換:
// Swapping variables in ECMAScript 5
let a = 1,
b = 2,
tmp;
tmp = a;
a = b;
b = tmp;
console.log(a); // 2
console.log(b); // 1
複製程式碼
in ECMAScript 6,陣列解構賦值可以用來交換兩個變數的值。
// Swapping variables in ECMAScript 6
let a = 1,
b = 2;
[ a, b ] = [ b, a ];
console.log(a); // 2
console.log(b); // 1
複製程式碼
賦值運算子左邊是解構模式語法,右邊是臨時建立的陣列字面量。使用解構可以很大程度上簡化程式碼,增加程式碼的可讀性,同時也省去了建立新變數的開銷。
Use Rest Items to Create a Clone
在ES5中,我們經常使用concat()
作為克隆陣列的簡便方法。concat()
方法原意是用來連線兩個陣列。當無引數呼叫時,它會返回當前這個陣列的克隆版本。
// cloning an array in ECMAScript 5
var colors = [ "red", "green", "blue" ];
var clonedColors = colors.concat();
console.log(clonedColors); //"[red,green,blue]"
複製程式碼
在ES6中,可以使用rest items完成這個需求。
// cloning an array in ECMAScript 6
let colors = [ "red", "green", "blue" ];
let [ ...clonedColors ] = colors;
console.log(clonedColors); //"[red,green,blue]"
複製程式碼
與concat()方法相比,使用解構能夠更加清晰的表達開發者的意圖,增加程式碼的易讀性。
Rest items 必須是解構陣列的最後一個入口(the last entry),後面跟comma會報錯。
Destructured Parameters
解構還有一個非常有用的case,就是用在函式引數上。
我們有時候會面對這樣的情景:一個JS函式除了接受幾個固定引數外,還會接受一些可選引數。通常我們可能會使用一個option
物件,將可選引數作為這個物件的屬性。
// properties on options represent additional parameters
function setCookie(name, value, options) {
options = options || {};
let secure = options.secure,
path = options.path,
domain = options.domain,
expires = options.expires;
// code to set the cookie
}
// third argument maps to options
setCookie("type", "js", {
secure: true,
expires: 60000
});
複製程式碼
這種方法是可用的,但是你並不能從函式定義上看出來這個函式期待的輸入引數是什麼,你需要去閱讀函式體。
解構提供了一種新的思路,你可以使用陣列解構或物件解構模式來代替這個option
命名引數。
function setCookie(name, value, { secure, path, domain, expires }) {
// code to set the cookie
}
setCookie("type", "js", {
secure: true,
expires: 60000
});
複製程式碼
解構模式裡的函式引數也像普通引數一樣,如果沒有傳入具體值,則置為undefined
。
解構引數擁有所有解構的能力。你可以使用預設值(default values),混合物件和陣列的模式(mix object and array patterns),以及不同於物件屬性的變數名(use variable names that differ from the properties you’re reading from)。
Destructured Parameters are Required
使用解構引數需要注意一點:預設情況下,如果在函式定義中的解構引數的位置上,你沒有傳入任何值,會發生報錯。
// Error!
setCookie("type", "js");
複製程式碼
出錯的原因是:解構引數實際上是解構宣告的簡寫,實際上JS引擎會對上述程式碼做以下工作:
function setCookie(name, value, options) {
let { secure, path, domain, expires } = options;
// code to set the cookie
}
複製程式碼
在解構賦值中,如果賦值運算子右側表示式的值是null
或者undefined
則會報錯,因為你無法從null
或者undefined
中讀取屬性。
因此setCookie()
函式在呼叫時,沒有傳入第三個引數會報錯。
如果程式碼中,這個解構引數是必需的,這樣做沒有問題。如果希望解構引數是可選的,你可以給解構引數本身提供預設值。
function setCookie(name, value, { secure, path, domain, expires } = {}) {
// ...
}
複製程式碼
Default Values for Destructured Parameters
像解構賦值一樣,可以給解構模式的引數提供預設值。
function setCookie(name, value,
{
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
} = {}
) {
// ...
}
複製程式碼
這樣你就可以不必去check傳入的解構引數有沒有包含特定的屬性,然後再給它正確的值。同時,因為整個解構引數本身也有預設值,因此這個函式引數是可選的。
建議在函式宣告時,使用解構引數來替代你的“option”物件。一方面可以清晰表達函式需要的引數,同時還能夠以較為簡便的方式為可選引數提供預設值。
再補充一種用法
function test(...args) {
console.log('====', args); //列印出來的args是陣列[1, 2, 3]
}
test(1, 2, 3)
複製程式碼
這個可以應用在使用apply的場景中,比如:
function bind(fn) {
return function (...args) {
fn.apply(this, args)
}
}
複製程式碼
如果不用解構,就需要把arguments處理成陣列
function bind(fn) {
return function () {
var args = [].concat(arguments)
fn.apply(this, args)
}
}
複製程式碼