[思] 當須要傳遞多個不定參數時,該如何設計 JavaScript 函數?

Issue 地址:github.com/aleen42/Per…git

其實咱們不少時候在設計一個 JavaScript 函數時,均可能會遇到這樣的一種狀況:參數數量不定,且通常會傳遞有多個。此時,咱們就會想該如何更優雅地設計函數來接收這些不定的參數?此 Issue 的提出就是爲了談談不才及劣者所知道的一些看法。github

對於這樣的狀況,咱們確定會想到一對函數:數組

一樣是爲方法調用指定 this,二者的區別在於傳遞不定參數的方式。app

爲了方便記憶,我一般會採用一種巧妙的方法去區分二者。call() 首字母爲 c,於是可看做以逗號(Comma)的方式來區分參數,而 apply() 首字母爲 a,於是也可看做是以數組(Array)的方式來區分參數。函數

這樣一看,官方彷佛已爲咱們預先提供了兩種通用的方式:ui

  • 以逗號分隔參數
  • 以數組組合參數

然而,若不去親身實現還不知道該怎麼設計函數才能更爲優雅?對此,不才與劣者認爲應該先實現數組組合的方式,然後再實現逗號分隔的方式。爲了能更好地說明,我將舉例 underscore 中關於 _.without()_.difference() 的實現。在討論實現以前,咱們先了解這兩個函數到底有何做用?其實,它們主要用於過濾數組中的部分紅員。所以,經過下面的代碼片斷咱們就能清晰地看到:this

var arr = [1, 2, 3, 4, 5];
var result = _.without(arr, 1, 2, 3);
console.log(result); /** => [4, 5] */複製代碼
var arr = [1, 2, 3, 4, 5];
var result = _.difference(arr, [1, 2, 3], [5, 6]);
console.log(result); /** => [4] */複製代碼

過濾成員須要經過不定的參數來告知函數,而二者惟一的區別與前述例子相似,也就是傳遞不定參數的方式不一樣。那麼,回到原來的問題,爲什麼咱們要先設計並實現以數組組合方式的函數呢?其實很簡單,緣由在於反過來實現會形成許多沒必要要的麻煩。spa

例如咱們先實現數組方式傳遞的 _.difference(),咱們就能夠經過簡單的數組組合來實現 _.without()prototype

_.difference = function (array) {
    /** * 把後續的參數嚴格鋪平成一個數組,即忽略不是包含在數組內的參數 * 如 _.difference(array, [1, 2], 3); 語句中的 3 */
    var rest = flatten(arguments, true, true, 1); 

    return _.filter(array, function (value) {
        return !_.contains(rest, value);
    });
};

_.without = function (array) {
    return _.difference(array, Array.prototype.slice.call(arguments, 1));
};複製代碼

但假若反過來,實現方式則變得更爲複雜:設計

_.without = function (array) {
    /** 若通過 `_.difference()` 的調用,則還須要把參數進行一層鋪平 */
    var rest = (this == 'difference') ?
        _.flatten(arguments, false, false, 1) :
        Array.prototype.slice.call(arguments, 1);

    return _.filter(array, function(value) {
        return !_.contains(rest, value);
    });
};

_.difference = function(array) {
    var args = _.flatten(arguments, true, true, 1);

    return _.without.apply('difference', args.unshift(array));
};複製代碼

綜上所述,以 _.without()_.difference() 爲例其複雜點顯然在於 _.without() 該如何區分究竟是否通過 _.difference() 來調用本身?由於針對這樣的兩種狀況,_.without() 都須要對參數進行不一樣的處理。簡單來講,_.without() 對於來自 _.difference() 的調用須要再進行一次鋪平(注:不才與劣者此處是經過指定 this 來提供一種區分的方式)。爲什麼?細緻想一想就會發現,產生如此的複雜在於舊版的 JavaScript 語法只能經過數組組合來傳遞若干個不定的參數,而沒法鋪開成逗號分隔的形式來傳遞。

那麼,既然語法存在缺陷,ES6 是否提供了新的方式去解決該問題呢?不才認爲,這偏偏體現出展開操做符(...,Spread Operator)的魅力所在。有了它,你就能夠直接展開若干個不定參數呢!

_.without = function (array) {
    var rest = Array.prototype.slice.call(arguments, 1);

    return _.filter(array, function(value) {
        return !_.contains(rest, value);
    });
};

_.difference = function(array) {
    var args = _.flatten(arguments, true, true, 1);
    args.unshift(array);

    return _.without.call(null, ...args);
};複製代碼
相關文章
相關標籤/搜索