使用解構的幾個騷操作

野生火鍋隊發表於2018-12-28

本文內容主要來自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)
  }
}
複製程式碼

相關文章