3 回答
TA貢獻2080條經驗 獲得超4個贊
Javascript中的參數重載有多個方面:
變量參數 - 您可以傳遞不同的參數集(包括類型和數量),并且函數的行為方式與傳遞給它的參數相匹配。
默認參數 - 如果參數未傳遞,則可以為參數定義默認值。
命名參數 - 參數順序變得無關緊要,您只需命名要傳遞給函數的參數。
以下是關于這些類別的參數處理的每個部分。
變量參數
因為javascript沒有對參數或需要的參數數量進行類型檢查,所以你可以myFunc()通過檢查參數的類型,存在或數量來實現一個可以適應傳遞給它的參數的實現。
jQuery一直這樣做。您可以將某些參數設置為可選,也可以根據傳遞給它的參數在函數中進行分支。
在實現這些類型的重載時,您可以使用幾種不同的技術:
您可以通過檢查聲明的參數名稱值是否為,來檢查是否存在任何給定的參數
undefined。您可以查看總數量或參數
arguments.length。您可以檢查任何給定參數的類型。
對于可變數量的參數,您可以使用
arguments偽數組來訪問任何給定的參數arguments[i]。
這里有些例子:
我們來看看jQuery的obj.data()方法。它支持四種不同的使用形式:
obj.data("key");obj.data("key", value);obj.data();obj.data(object);每一個觸發一個不同的行為,并且不使用這種動態形式的重載,將需要四個單獨的功能。
以下是用英語辨別所有這些選項的方法,然后我將它們全部合并到代碼中:
// get the data element associated with a particular key valueobj.data("key");如果傳遞給的第一個參數.data()是一個字符串而第二個參數是undefined,則調用者必須使用此表單。
// set the value associated with a particular keyobj.data("key", value);如果第二個參數未定義,則設置特定鍵的值。
// get all keys/valuesobj.data();
如果沒有傳遞參數,則返回返回對象中的所有鍵/值。
// set all keys/values from the passed in objectobj.data(object);
如果第一個參數的類型是普通對象,則設置該對象的所有鍵/值。
以下是如何在一組javascript邏輯中組合所有這些:
// method declaration for .data()
data: function(key, value) {
if (arguments.length === 0) {
// .data()
// no args passed, return all keys/values in an object
} else if (typeof key === "string") {
// first arg is a string, look at type of second arg
if (typeof value !== "undefined") {
// .data("key", value)
// set the value for a particular key
} else {
// .data("key")
// retrieve a value for a key
}
} else if (typeof key === "object") {
// .data(object)
// set all key/value pairs from this object
} else {
// unsupported arguments passed
}
},這種技術的關鍵是確保您想要接受的所有形式的參數都是唯一可識別的,并且從不會混淆調用者使用哪種形式。這通常需要對參數進行適當排序,并確保參數的類型和位置有足夠的唯一性,您可以始終確定正在使用哪種形式。
例如,如果您有一個帶三個字符串參數的函數:
obj.query("firstArg", "secondArg", "thirdArg");您可以輕松地使第三個參數可選,您可以輕松地檢測到該條件,但您不能只使第二個參數可選,因為您無法分辨調用者的哪一個意味著要傳遞,因為無法確定是否第二個參數意味著是第二個參數或第二個參數被省略,所以第二個參數的位置實際上是第三個參數:
obj.query("firstArg", "secondArg");obj.query("firstArg", "thirdArg");由于所有三個參數都是相同的類型,因此您無法區分不同的參數,因此您不知道調用者的意圖。使用此調用樣式,只有第三個參數可以是可選的。如果你想省略第二個參數,它必須作為null(或其他一些可檢測的值)傳遞,你的代碼會檢測到:
obj.query("firstArg", null, "thirdArg");這是一個可選參數的jQuery示例。兩個參數都是可選的,如果沒有傳遞則采用默認值:
clone: function( dataAndEvents, deepDataAndEvents ) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
return this.map( function () {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
});},這是一個jQuery示例,其中參數可以丟失,或者三種不同類型中的任何一種,它們為您提供了四種不同的重載:
html: function( value ) {
if ( value === undefined ) {
return this[0] && this[0].nodeType === 1 ?
this[0].innerHTML.replace(rinlinejQuery, "") :
null;
// See if we can take a shortcut and just use innerHTML
} else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
jQuery.cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
} else if ( jQuery.isFunction( value ) ) {
this.each(function(i){
var self = jQuery( this );
self.html( value.call(this, i, self.html()) );
});
} else {
this.empty().append( value );
}
return this;},命名參數
其他語言(如Python)允許人們傳遞命名參數作為傳遞一些參數并使參數獨立于傳遞順序的方法.Javascript不直接支持命名參數的特性。通常在其位置使用的設計模式是傳遞屬性/值的映射。這可以通過傳遞具有屬性和值的對象來完成,或者在ES6及更高版本中,您實際上可以傳遞Map對象本身。
這是一個簡單的ES5示例:
jQuery $.ajax()接受一種用法,你只需要傳遞一個參數,這是一個帶有屬性和值的常規Javascript對象。您傳遞的屬性確定將哪些參數/選項傳遞給ajax調用。有些可能是必需的,許多是可選的。由于它們是對象的屬性,因此沒有特定的順序。實際上,可以在該對象上傳遞30多個不同的屬性,只需要一個(url)。
這是一個例子:
$.ajax({url: "http://www.example.com/somepath", data: myArgs, dataType: "json"}).then(function(result) {
// process result here});在$.ajax()實現內部,它可以只詢問傳入對象上傳遞的屬性并將其用作命名參數。這可以通過使用for (prop in obj)或通過將所有屬性放入數組中Object.keys(obj)然后迭代該數組來完成。
當有大量參數和/或許多參數是可選的時,這種技術在Javascript中非常常用。注意:這會對實現函數負責,以確保存在最小有效參數集,并為調用者提供一些調試反饋,如果傳遞的參數不足則會丟失哪些內容(可能通過拋出有用錯誤消息的異常) 。
在ES6環境中,可以使用解構來為上面傳遞的對象創建默認屬性/值。這篇參考文章將對此進行更詳細的討論。
這是該文章的一個例子:
function selectEntries({ start=0, end=-1, step=1 } = {}) {
···};這將創建默認屬性和值start,end并step傳遞到一個對象的屬性selectEntries()的功能。
函數參數的默認值
在ES6中,Javascript為參數的默認值添加了內置語言支持。
例如:
function multiply(a, b = 1) {
return a*b;}multiply(5); // 5TA貢獻1801條經驗 獲得超16個贊
嚴格意義上講,你不能做方法重載。不像它支持的方式java或c#。
問題是JavaScript本身不支持方法重載。因此,如果它看到/解析兩個或多個具有相同名稱的函數,它將只考慮最后定義的函數并覆蓋之前的函數。
我認為適合大多數情況的方式之一是 -
讓我們說你有方法
function foo(x){}您可以定義一個新方法,而不是在javascript中無法實現的重載方法
fooNew(x,y,z){}然后修改第一個函數如下 -
function foo(x){
if(arguments.length==2)
{
return fooNew(arguments[0], arguments[1]);
}}如果您有許多這樣的重載方法,請考慮使用switch而不僅僅是if-else語句。
(更多細節)PS:以上鏈接轉到我的個人博客,其中包含有關此內容的其他詳細信息。
添加回答
舉報
