2014-03-29 60 views
3
String.prototype.contains = function(str) { 
    return this.indexOf(str) !== -1; 
}; 

此代碼段的確擴展了String.prototype
它與函數調用如'foobar'.contains('foo');
但是,如果它作爲一個函數傳遞,而不是調用它,它不能很好地工作:將函數綁定到String.prototype,因此它總是綁定到字符串

var str = 'foobar'; 
['foo', 'bar'].every(str.contains); 
TypeError: Object [object global] has no method 'indexOf' 

我知道你可以這樣做:

['foo', 'bar'].every(str.contains.bind(str)); 

或類似的東西:

['foo', 'bar'].every(function(item) { return str.contains(item); }); 

但他們只是讓我感到尷尬。
Constructor功能我創建的,雖然它不以這種方式工作:如果有一種方法來

function Foo(myStr) { 
    var self = this; // Line added 
    this.myStr = myStr; 

    this.contains = function(fragment) { 
     return self.myStr.indexOf(fragment) !== -1; // this changed to self 
    }; 
} 

我想知道:

function Foo(myStr) { 
    this.myStr = myStr; 

    this.contains = function(fragment) { 
     return this.myStr.indexOf(fragment) !== -1; 
    }; 
} 
var someFoo = new Foo('foobar'); 
['foo', 'bar'].every(someFoo.contains) 
TypeError: Cannot call method 'indexOf' of undefined 

我能做到這一點,使其工作擴展String.prototype,這樣我就不必將'someString'.contains綁定到'someString'每次我將它用作函數而不調用它。

+1

你應該* *這樣做會讓你感到尷尬的方式?強硬。 – Jon

+0

@Jon因爲我可以像在我創建的Foo類中那樣做。我使用FP很多,如果我沒有得到與String相關的'contains'函數,我覺得我的程序會犯很多錯誤,因爲這樣的用法遍佈我的程序... – octref

+0

字符串沒有辦法,我懷疑它爲MyString類型會很有用。 – Tibos

回答

2

試試這個:

Object.defineProperty(String.prototype, "contains", { 
    get: function() { 
     return (function(str) { 
      return this.indexOf(str) !== -1; 
     }).bind(this); 
    } 
}); 

它定義了一個新的屬性與getter,每意思當你「獲得」該功能時,例如在['foo', 'bar'].every(str.contains);中,上面定義的功能將得到在這種情況下,該函數的返回值將返回爲str.contains。函數和你的函數是一樣的,只有我們在getter中綁定this這是字符串,這就是我們想要的。

如果Object.defineProperty沒有在您的瀏覽器(或任何人使用您的代碼)中定義,您可以使用__defineGetter__來代替。

一個完整的解決方案應該是這樣的:

addPropertyWithGetter = function(object, property) { 

    getter = function() { 
     return (function(str) { 
      return this.indexOf(str) !== -1; 
     }).bind(this); 
    } 

    if (_.isFunction(Object.defineProperty)) { 
     return Object.defineProperty(object, property, { 
      get: getter, 
     }); 
    } else { 
     object.__defineGetter__(property, getter); 
    } 
} 

和使用:

addPropertyWithGetter(String.prototype, "contains")

+0

必須向你表示歉意。我很抱歉,但我不知何故沒有看到有關你答案的通知。這很好用 - 非常感謝! – octref

1

Array.prototype.every()的第二個參數是thisArg值作爲此執行回調時使用)。

所以,你可以用做:

['foo', 'bar'].every(str.contains, str); 

爲了固定代碼:

function Foo(myStr) { 
    this.contains = function(fragment) { 
     // myStr is accessible here 
     return myStr.indexOf(fragment) !== -1; 
    }; 
} 
var someFoo = new Foo('foobar'); 
['foo', 'bar'].every(someFoo.contains); 
+0

感謝您的答案。但我想知道是否有方法將'contains'函數綁定到字符串,就像我將它綁定到我的'Foo'類一樣。換句話說,當我使用str.contains時,這個Arg自動綁定到str。 – octref