分配RegExp.测试一个变量

Assigning RegExp.test to a variable

本文关键字:一个 变量 RegExp 测试 分配      更新时间:2023-09-26

以下代码:

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

抛出" TypeError: can't convert undefined to object "

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

更新:

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

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

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

例如:

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 RegExp原型对象的属性

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

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

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

或使用callapply:

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

由于我在所有评论中基本上都试图回答这个问题,所以让我们总结一下到目前为止所涉及的所有内容。

当你这样做的时候:

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

您正在将RegExp对象中的名为test的方法分配给名为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指针设置为正则表达式对象,然后使用该this指针执行r方法。

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

主要编辑:现在我已经看到了你的更新,它消除了我原来的帖子谈到的问题,我意识到问题是test函数在运行时需要与对象相关联。regex对象后的标准点符号会自动将test中的this设置为等于该对象。当您单独调用它作为r("A");时,this将被设置为窗口对象,这不起作用并给出一个错误。(这对某些函数来说并不重要,但是test需要它的this对象是一个要操作的正则表达式。)

您可以通过使用.call():

显式设置this来使其工作
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")语法,只需添加一个包装器。