2014-04-27 22 views
4

檢查這個fiddle或下面的代碼沒有概念:在JavaScript超載

function abc(s) { 
    console.log('in abc(s)'); 
} 

function abc(s, t) { 
    console.log('in abc(s,t)'); 
} 

abc('1'); 

這個問題的輸出總是in abc(s,t)

是否有人可以給我解釋一下什麼在這裏,爲什麼回事?

+5

發生什麼事是第二個函數聲明完全覆蓋了第一個函數聲明。爲什麼JS中沒有重載這樣的概念。 – m90

+0

定義的最新函數覆蓋符號表中的前一個函數 – thefourtheye

+0

那麼它總是調用它找到的最後一個函數? – SharpCoder

回答

4

首先,JavaScript中沒有方法重載支持(請參閱@ 6502 workaround)。

其次,描述您遇到什麼,在JavaScript中,最後聲明的函數(與相同名)被調用,因爲前者已被覆蓋,它涉及到JavaScript Hoisting

再次嘗試重新排序函數的聲明,看看輸出結果:

function abc(s, t) { 
    console.log('in abc(s,t)'); 
} 

function abc(s) { 
    console.log('in abc(s)'); 
} 

abc('1'); 
6

在Javascript中沒有超載的概念。

然而,您可以編寫一個函數,通過使用arguments值來檢查已傳遞多少個參數。

function foo(s, t) { 
    if (arguments.length == 2) { 
     ... 
    } else { 
     ... 
    } 
} 

所有參數的函數簽名預期但沒有被接收爲undefined傳遞給調用者。您也可以通過簡單訪問與arguments[i]傳遞的第n個參數來編寫可變參數函數。但請注意,arguments不是Javascript數組,因此並非所有數組方法都可用。

關於能夠多次重新定義同一個函數而沒有錯誤因爲規則很奇怪,所以解釋起來有點複雜。

一個簡單的解釋是你可以想到的是function是一個可執行語句,就像它在Python中一樣,所以最後一個函數定義獲勝。然而,因爲不同於Python的,下面是合法的Javascript代碼,這將是錯誤的:

console.log(square(12)); 
function square(x) { return x*x; } 

即你可以調用一個函數在被定義之前(在腳本行:當然輸入這兩條線一個Javascript控制檯不會工作)。

稍微更正確的解釋是編譯器首先解析所有函數定義(最後的勝利)然後開始執行代碼。如果你沒有把function放在if裏面,這個心理模型就可以工作,因爲在這種情況下實際發生的事情是依賴於實現的(並且我不是在談論瘋狂的IE,但即使是FF和Chrome也會做不同的事情)。只是不要那樣做。

你甚至可以使用的形式

var square = function(x) { return x*x; } 

在這種情況下它的時候通過它的流時執行的「函數式」的變量的簡單任務(所以這是確定放置不同函數在不同的if分支中的實現,但在分配實現之前無法調用該函數)。

+0

注意事項:雖然這是真的,你不能'arguments.forEach(func)',你仍然可以做'[] .forEach.call(arguments,func)' –

1

在javascript中,只有一個具有任何給定名稱的函數,並且如果聲明具有相同名稱的多個函數,則聲明的最後一個函數將是活動的函數。

但是,您可以測試傳遞給您的函數的參數,並實現函數重載旨在處理的許多相同類型的行爲。事實上,在某些情況下,你可以做更多。

在你的具體的例子:

function abc(s, t) { 
    // test to see if the t argument was passed 
    if (t !== undefined) { 
     console.log('was called as abc(s,t)'); 
    } else { 
     console.log('was called as abc(s)'); 
    } 
} 

abc('1');  // outputs 'was called as abc(s)' 
abc('1', '2'); // outputs 'was called as abc(s,t)' 

但是,你還可以得到更多,更多創意(和有用)。

例如,jQuery .css()方法可以被稱爲五種不同的方式。

.css(propertyName) 
.css(propertyNames) 
.css(propertyName, value) 
.css(propertyName, function(index, value)) 
.css(properties) 

.css()所述方法中的代碼檢查的類型和自變量數目找出它被稱爲哪種方式,並且因此準確地進行什麼操作。

讓我們看看如何做才能找出其中5所形成這一功能正在被使用:

css: function(prop, value) { 
    // first figure out if we only have one argument 
    if (value === undefined) { 
     if (typeof prop === "string") { 
      // we have a simple request for a single css property by string name 
      // of this form: .css(propertyName) 
     } else if (Array.isArray(prop)) { 
      // we have a request for an array of properties 
      // of this form: .css(propertyNames) 

     } else if (typeof prop === "object") { 
      // property-value pairs of css to set 
      // of this form: .css(properties) 
     } 
    } else { 
     if (typeof value === "function") { 
      // of this form: .css(propertyName, function(index, value)) 
     } else { 
      // of this form: .css(propertyName, value) 
     } 
    } 
} 

您還可以實現可選的參數。例如,jQuery的.hide()可以接受許多形式。其中一種形式是.hide([duration ] [, complete ]),其中持續時間和完成功能都是可選的。你可以傳遞任何東西,只是一個持續時間或持續時間和完成回調函數。這可以實現這樣的:

hide: function(duration, fn) { 
    // default the duration to zero if not present 
    duration = duration || 0; 
    // default the completion function to a dummy function if not present 
    fn = fn || function() {}; 

    // now the code can proceed knowing that there are valid arguments for both 
    // duration and fn whether they were originally passed or not 
} 

我發現使用這些變量參數的最有效的方法之一是,允許代碼以支持各種不同的參數類型,但不管是什麼狀態你的論點進來,你可以通過他們,因爲你有他們,而不必將其轉換爲一些通用類型。例如,以JavaScript this implementation of a set object,所述.add()方法可以利用這些不同形式的參數的所有:

s.add(key) 
s.add(key1, key2, key3) 
s.add([key1, key2, key3]) 
s.add(key1, [key8, key9], key2, [key4, key5]) 
s.add(otherSet)    // any other set object 
s.add(arrayLikeObject)  // such as an HTMLCollection or nodeList 

這兩者接受可變數量的參數,並且它接受多個不同類型的每個參數,它會根據傳遞給它的內容進行調整。因此,您可以通過鍵列表,鍵列數組,另一組鍵列,僞數組或任何這些類型的混合來初始化集合。在內部,代碼只是遍歷每個傳遞給函數的參數,檢查參數的類型並相應地執行。

您可以看到代碼here on GitHub瞭解更多信息。