将函数绑定到String.prototype,以便它始终绑定到字符串

时间:2014-03-29 16:43:44

标签: javascript

String.prototype.contains = function(str) {
    return this.indexOf(str) !== -1;
};

此代码段确实展开了String.prototype 它适用于'foobar'.contains('foo')等函数调用 但如果它作为一个函数传递,而不是调用它,它就不能很好地工作:

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) {
    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

我可以这样做以使其有效:

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
    };
}

我想知道是否有扩展String.prototype的方法,以便我每次使用时都不必将'someString'.contains绑定到'someString'作为一个没有调用它的函数。

2 个答案:

答案 0 :(得分: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")

用法:

{{1}}

答案 1 :(得分: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);