调用时,分配给变量或函数参数的对象方法会失败

时间:2013-06-12 00:19:38

标签: javascript functional-programming

我现在正在学习javascript,对我来说似乎是很漂亮的函数式语言,这是PHP的精彩之举,我应该早点做到这一点。虽然,我无法想出这个:

var v1 = (/[abc]/).test;
v1('a');

test method called on incompatible undefined,我正在尝试将该正则表达式的测试方法存储到变量中并稍后调用它。

但它适用于我自己的功能:

function foo(){
    return 'I\'m foo';
}

var f = foo;
f(); // returns I'm foo

它也应该适用于方法,因为函数只是父对象的方法,对吧?

最终,我尝试这个的原因是能够写出这样的东西:

var a = ['a', 'b', 'c'];
a.every( (/[abc]/).test );

检查每个数组成员与该正则表达式。

为什么这不起作用?传递内置函数是否有限制?或者我只是做错了什么?

PS:如果你现在磨牙并闷闷不乐的做法,搞好习惯,我只是在玩。但我也想听听他们的消息。

5 个答案:

答案 0 :(得分:3)

如果只存储一个方法,它不带有对象的引用 - 它只存储对.test方法的引用,但没有特定的对象。请记住,方法“只是”对象的属性,并且存储对方法的引用不会将其绑定到该对象,它只存储对该方法的引用。

要在特定对象上调用该方法,必须使用该对象调用它。

您可以创建自己的函数,在所需的对象上调用方法,如下所示:

var v1 = function(x) {
    return /[abc]/.test(x);
}

然后,当你这样做时:

v1('a');

它将在你的函数中执行相应的操作:

/[abc]/.test('a');

但是,为什么你这样做还不完全清楚,因为你也可以定义正则表达式并多次调用.test():

var myRegex = /[abc]/;
console.log(myRegex.test('a'));
console.log(myRegex.test('b'));
console.log(myRegex.test('z'));

答案 1 :(得分:3)

  

它适用于我自己的功能

您没有在函数中使用this。考虑这个例子:

var obj = {
    foo: 42,
    bar: function() {
        alert(this.foo);
    }
};
var f = obj.bar;
f(); // will alert `undefined`, not `42`
  

它也应该适用于方法,因为函数只是父对象的方法,对吧?

“方法”只是分配给对象属性的函数的通俗术语。功能是独立的值。与功能分配的对象没有任何关联。这怎么可能,因为一个函数可以分配给多个对象?

  

为什么这不起作用?

在{strong>运行时中确定函数内部this所指的内容。因此,如果您将函数分配给变量并稍后调用

var v1 = (/[abc]/).test;
v1('a');
函数内的

this将引用window,而不是正则表达式对象。

您可以使用.bind [MDN]this明确绑定到特定值:

var a = ['a', 'b', 'c'];
var pattern = /[abc]/;
a.every(pattern.test.bind(pattern));

请注意,由于.bind返回一个函数,因此使用函数表达式的唯一优势是它的写入时间稍短。


  

传递内置函数是否有限制?

不,每个方法/函数都存在问题,因为这是函数的工作方式。关于内置函数的好处是它们经常明确告诉你何时this指的是错误类型的对象(通过抛出错误)。


Learn more about this.

答案 2 :(得分:1)

test函数希望this成为正则表达式。表达式/[abc]/.test给出了一个未绑定的函数(它不记得它属于/[abc]/)。当您像调用它一样调用它时,this将为undefined,函数将失败。

您可以使用bind让函数记住它所属的对象:

var v1 = /[abc]/.test.bind(/[abc]/);

var v1 = RegExp.prototype.test.bind(/[abc]/);

答案 3 :(得分:0)

您对该方法的引用已经失去了对它的方法的了解。 这不仅仅是JS工作的好方法。

你可以这样做:

var v1 = /[abc]/;
v1.test('a');    

如果必须封装测试方法,那么你可以这样做:

var v1 = function(str){
    return /[abc]/.test(str);
};
v1('a');

答案 4 :(得分:0)

我不知道这是否是可接受的解决方案,但您可以这样做:

v1 = function(exp) { return (/[abc]/).test(exp); }
v1('a');