2010-10-23 27 views
15

我正在查看MooTools源代碼,以瞭解它的.implement().extend()實用程序。MooTools的Function.prototype.overloadSetter()是做什麼的?

各的定義是指這樣定義的函數:

var enumerables = true; 
for (var i in {toString: 1}) enumerables = null; 
if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor']; 

Function.prototype.overloadSetter = function(usePlural){ 
    var self = this; 
    return function(a, b){ 
     if (a == null) return this; 
     if (usePlural || typeof a != 'string'){ 
      for (var k in a) self.call(this, k, a[k]); 
      if (enumerables) for (var i = enumerables.length; i--;){ 
       k = enumerables[i]; 
       if (a.hasOwnProperty(k)) self.call(this, k, a[k]); 
      } 
     } else { 
      self.call(this, a, b); 
     } 
     return this; 
    }; 
}; 

不過,我有一個艱難的時間瞭解它做什麼。

你能解釋一下這個函數是如何工作的嗎?

回答

29

overloadSetter

overloadSetter,與overloadGetter一起,是兩個函數的裝飾方法。 overloadSetter函數用於將具有簽名fn(key, value)的函數轉換爲可接受對象參數的函數,即:fn({key: value})

爲了做到這一點,overloadSetter必須包裝原來的功能。該包裝函數的簽名爲fn(a, b),這是fn(key, value)的快捷方式。這實際上成爲原始函數的新重載版本。

這個重載函數做的第一件事是檢查傳遞的key參數(a)是否是字符串類型。如果它不是一個字符串,該函數假定我們正在傳遞一個對象。因此,它遍歷對象中的每個鍵值對,並將原始函數應用於其中。另一方面,如果它是一個字符串,它只是將該函數應用於參數ab的值。

爲了舉例說明,假設我們有以下功能:

var fnOrig = function(key, value){ 
    console.log(key + ': ' + value); 
}; 

var fnOver = fnOrig.overloadSetter(); 

fnOver('fruit', 'banana'); 
fnOver({'fruit': 'banana', 'vegetable': 'carrot'}); 

在第一次調用時,fnOver函數調用時帶有兩個參數,一個鍵和一個值。當函數檢查參數值a的類型時,它會看到它是一個字符串。因此,它將簡單地調用原始的fnOrig函數:fnOrig.call(this, 'fruit', 'banana')。我們的控制檯輸出是'fruit: banana'

對於第二次調用,使用對象參數調用fnOver函數。由於我們傳遞了一個對象而不是字符串,因此fnOver將遍歷此對象的成員,併爲其中的每個成員調用fnOrig函數。因此,在這種情況下,fnOrig將被調用兩次:fnOrig.call(this, 'fruit', 'banana')fnOrig.call(this, 'vegetable', 'carrot')。我們的控制檯輸出是'fruit: banana''vegetable: carrot'

額外

裏面的包裝函數,你會看到有針對usePlural值的檢查。這是overloadSetter方法本身的一個參數。如果將此值設置爲true,則新函數將把所有參數視爲對象。這意味着即使你傳遞了一個字符串鍵參數,它仍然會作爲一個對象來處理。

其他的事情,在enumerables代碼前奏曲實際方法的聲明,有沒有因爲它修復了一些瀏覽器,其中天然Object方法不是在for/in循環中列舉的問題,即使對象本身實現它自己的版本。

+6

雖然這有點不太可能改變,但我應該指出這是一種私人/內部方法,並且依賴於API的編寫代碼可能無法經受時間的考驗(暫時在1.3版本中工作) – 2010-10-25 13:10:25

+0

無證,所以沒有承諾。使用風險自負:) – seanmonstar 2010-10-25 17:19:59

+1

感謝您的好評。 @Dimitar,seanmonstar:沒關係,我沒有打算使用它,我只是想了解這個函數是如何工作的以及它做了什麼。 – 2010-10-27 14:17:01

3

是把我抓我的頭一會兒部分是

var enumerables = true; for (var i in {toString: 1}) enumerables = null;

部分,它原來是爲DontEnum錯誤,某些瀏覽器進行測試。乍一看,好像它應該只是設置enumerablesnull,但與DontEnum錯誤toString被抑制(錯誤,因爲該對象的prototype.toStringDontEnum標誌)和enumerables留作true

overloadSetter(或者更確切地說是函數)必須一次檢查一個DontEnum錯誤影響的七個屬性,以查看它們是否存在於對象參數中。

+0

如果你想知道如果你在存在DontEnum錯誤的情況下設置'hasOwnProperty'屬性會發生什麼,你是正確的:檢查受影響的屬性將使用你提供的' hasOwnProperty',即使你以某種方式找到覆蓋原型函數的好理由,它幾乎肯定不是你想要的。 – LHMathies 2011-01-20 11:45:16