Присвоение RegExp.test переменной - PullRequest
2 голосов
/ 05 августа 2011

Следующий код:

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

Выдает «Ошибка типа: невозможно преобразовать неопределенное в объект»

Как еще можно назначить функцию теста для переменной для передачи в функции, последующая оценка и т. д.?(Без включения регулярного выражения в другую функцию)

Обновление:

Перед ответом рассмотрите этот бит действительного кода:

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

Ответы [ 3 ]

6 голосов
/ 05 августа 2011

Это связано со значением 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 Свойства объекта-прототипа RegExp

В следующих описаниях функций, являющихся свойствами объекта-прототипа RegExp, фраза «этот объект RegExp» относится к объекту, являющемуся значением this для вызова функции; Исключение TypeError генерируется, если значение this не является объектом или объектом, для которого значение внутреннего свойства [[Class]] не равно "RegExp".

Однако вы можете привязать метод 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
2 голосов
/ 05 августа 2011

Поскольку я по существу пытался ответить на этот вопрос во всех моих комментариях, давайте подытожим все, что мы уже рассмотрели, в реальном ответе.

Когда вы сделаете это:

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.

Я действительно не знаю, почему вы хотите это сделать, но, надеюсь, это поможет объяснить все.

0 голосов
/ 05 августа 2011

ОСНОВНОЕ РЕДАКТИРОВАНИЕ: Теперь, когда я увидел ваше обновление, которое устранило проблему, о которой говорилось в моем первоначальном посте, я понял, что проблема заключается в том, что функция 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"), просто добавьте оболочку.

...