不定引數(rest 引數 ...)
阿新 • • 發佈:2018-12-21
不定引數
如何實現不定引數
使用過 underscore.js 的人,肯定都使用過以下幾個方法:
_.without(array, *values) //返回一個刪除所有values值後的array副本
_.union(*arrays) //返回傳入的arrays(陣列)並集
_.difference(array, *others)//返回來自array引數陣列,並且不存在於other 陣列
...
這些方法都有一個共同點,就是可以傳入不定數量的引數,例如,我想刪除掉 array
中的 value1,value2
,可以這樣使用 , _.without(array,value1,value2);
那麼,這個需要怎樣才能做到呢?
我們知道,js 中 function
裡面,有一個 arguments
引數,它是一個類陣列,裡面包含著呼叫這個方法的所有引數,所以可以這樣處理:
_.without = function() { if (arguments.length > 0) { var array = arguments[0]; var values = []; for (var i = 1; i < arguments.length; i++) { values.push(arguments[i]); } //這樣得到了array,和values陣列,便可以進一步處理了 } };
上面只是打個比方,想要支援不定引數,我們要做的就是把固定引數和動態引數從 arguments 中分離出來。
但是,我們這樣寫的話,需要在每個支援不定引數的函式裡,都 copy 這樣一段程式碼,這樣實在不是很優雅。所以需要封裝成一個通用的函式。
我們直接看看 underscore 是封裝的好了。
restArgs 原始碼
var restArgs = function(func, startIndex) { //startIndex ,表示幾個引數之後便是動態引數 startIndex = startIndex == null ? func.length - 1 : +startIndex; return function() { var length = Math.max(arguments.length - startIndex, 0); //處理arguments,將動態引數儲存進rest陣列 var rest = Array(length); for (var index = 0; index < length; index++) { rest[index] = arguments[index + startIndex]; } //處理0,1,2三種情況,這裡要單獨處理,是想優先使用call,因為,call的效能比apply要好一點 switch (startIndex) { case 0: return func.call(this, rest); case 1: return func.call(this, arguments[0], rest); case 2: return func.call(this, arguments[0], arguments[1], rest); } //如果startIndex不是0,1,2三種情況,則使用apply呼叫方法,將args作為引數,args將為陣列[固定引數 ,rest]; var args = Array(startIndex + 1); for (index = 0; index < startIndex; index++) { args[index] = arguments[index]; } args[startIndex] = rest; return func.apply(this, args); }; }; //這裡without主要的邏輯處理方法,作為引數,傳給restArgs,在restArgs中處理完引數後,使用call或apply呼叫邏輯處理方法 // 這時候接受到引數otherArrays,已經是一個數組了,包含了之前的動態引數。 _.without = restArgs(function(array, otherArrays) { //處理without具體事件 });
underscore.js 中利用 js 高階函式的特性,巧妙的實現了動態引數
如果要使某函式支援不定引數,只需要將該函式作為引數,傳入 restArgs 中即可,例如:
function addByArray(values) {
var sum = 0;
for (var i = 0; i < values.length; i++) {
sum += values[i];
}
return sum;
}
var add = restArgs(addByArray);
//呼叫:
addByArray([2, 5, 3, 6]); //16
add(2, 5, 3, 6); //16
ES6 不定引數 (...)
ES6 引入了 rest 引數,(形式為"...變數名"),用於獲取多餘引數,這樣就不需要使用 arguments 物件來實現了
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3); // 10
總結
在 underscore 中,restArgs 只是為了支援不定引數。實際使用中,也許我們都是直接使用 ES6,或用 babel 將 ES6 轉成 ES5 來支援不定引數
不過,如果是在非 es6 的環境下,知道有這麼一種實現方式,也是挺好的。
:)