以下代码:
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
答案 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
或使用call
或apply
:
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")
语法,只需添加一个包装器。