将RegExp.test分配给变量

时间:2011-08-05 04:01:26

标签: javascript regex functional-programming

以下代码:

var r = /^[0-9A-Z]$/.test;
r("A")

引发'TypeError:无法将undefined转换为object'

我怎样才能将测试函数分配给变量,传递函数,后期评估等? (不将正则表达式包装在另一个函数中)

更新

在回答之前考虑一下这段有效的代码:

var o = { f: function() { return 1 } };
var a = o.f;
var b = a();     // b = 1

3 个答案:

答案 0 :(得分:6)

它与this方法中的test值有关。

例如:

var obj = {
  method: function () { return this === obj }
};

obj.method(); // true

var method = obj.method;
method(); // false

如果您将test方法称为“函数” - 例如r(); - ,则this值将引用undefined(对于内置或ECMAScript 5中的严格函数,在上面的示例this中将引用全局对象。)

调用任何RegExp.prototype this值不属于RegExp对象的方法,总是会产生此TypeError异常,引用规范:

15.10.6 Properties of the RegExp Prototype Object

  

在下面对作为RegExp原型对象属性的函数的描述中,短语“this RegExp object”指的是调用该函数的该值的对象;如果此值不是[[Class]]内部属性的值不是“RegExp”的对象或对象,则抛出TypeError异常。

但是,您可以使用test方法将r方法绑定到Function.prototype.bind函数:

var re = /^[0-9A-Z]$/,
    r = re.test.bind(re);

r("A"); // true

或使用callapply

var r = re.test;
r.call(re, "A"); // true

答案 1 :(得分:2)

由于我在所有评论中一直试图回答这个问题,让我们总结一下到目前为止我们在实际答案中所涵盖的所有内容。

执行此操作时:

var r = /^[0-9A-Z]$/.test;

您正在将名为test的方法从RegExp对象分配给名为r的变量。这只是一种方法分配。与您创建的特定正则表达式对象没有任何关联。事实上,r == RegExp.prototype.test

然后当你尝试这行代码时:

r("A")

您正在尝试执行RegExp.prototype.test并将其传递给"A",但您没有适当的对象上下文。当测试函数运行时,this指针不会指向正则表达式对象,它将指向全局对象(在浏览器中是window对象)。

在你的o,a和b代码示例中,它的工作原理是因为您所做的只是调用不引用实例数据的函数,并且根本不使用this指针(因此它没有设置并不重要)到适当的对象上下文)。正则表达式方法不是这种情况。它需要它的实例数据(例如它的this指针指向一个真正的正则表达式对象。)

可以采用方法点并添加适当的this指针,但我不知道为什么在这个特定的例子中它会有用。例如,您可以这样做:

var re = /^[0-9A-Z]$/;
var r = re.test;
r.call(re);

this指针设置为正则表达式对象,然后使用r指针执行this方法。

我真的不知道你为什么要这样做,但希望这有助于解释事情。

答案 2 :(得分:0)

主要编辑:现在我已经看到了你的更新,它删除了我原来的帖子所讨论的问题,我意识到问题是test函数在运行时需要与对象关联。正则表达式对象后的标准点表示法将自动将this内的test设置为等于该对象。当您将其自身称为r("A");时,this将被设置为窗口对象,该窗口对象不起作用并产生错误。 (这对于某些函数无关紧要,但test需要其this对象作为正则函数才能运行。)

您可以使用this

明确设置.call(),使其有效
var re = /^[0-9A-Z]$/;
var rf = re.test;

alert(rf.call(re,"A"));     // displays 'true'
alert(rf.call(/blah/,"A")); // displays 'false'

但这看起来很傻。我问你为什么不能这样做:

var r = /^[0-9A-Z]$/;
r.test("A");
r.test("B");

这使您可以保留正则表达式的一个副本,而不需要自己的函数包装器。如果你真的想要r("A")语法,只需添加一个包装器。