2015-01-29 2 views
5

На вводе следующего вызова функции в хромированную консоль:Javascript: Insane boolean test с '!' Оператор

(function(regex, str){ 
    console.log(regex.test(str)) 
    console.log(!regex.test(str)) 
    console.log(! regex.test(str)) 
    console.log(!regex.test(str)) 
    console.log(! regex.test(str)) 
})(new RegExp("new", "gmi"), "new") 

я получаю следующие результаты:

true 
true 
false 
true 
false 

Может кто-то объяснить, почему третьи и 5-тесты вернуться false? И почему Первый и Второй оба возвращают истину.

+2

более запутанным является то, как первые два обеспечивают тот же результат – DLeh

+0

@DLeh Я вытягиваю свои волосы. Реплицировать этот результат практически невозможно. –

+0

@JoeButler, если вы выберете модификатор «g», он больше не будет странным. – Pointy

ответ

10

Вы включаете модификатор «g», поэтому объект регулярного выражения поддерживает состояние выполнения совпадения. Другими словами, каждый вызов не совпадает.

Ваш первый вызов соответствует строке "new", а регулярное выражение обновляет позицию до конца строки. Следующий матч не удастся (так что вы видите true за !regexp.test(str)). Он терпит неудачу, потому что строка «новый» не появляется в конце строки «новый».

Теперь мы сбегаем с конца строки, поэтому следующий тест начинается как первый. Он снова совпадает, поэтому ваш ! превращает это true в false. Тот, который после этого не соответствует, и один после , что начнется снова и будет соответствовать.

Обратите внимание, что пробелы вокруг ! в тестах не имеют абсолютно никакого отношения к поведению.

редактировать — попробовать этот вариант:

(function(regex, str){ 
    console.log(regex.test(str) + " - " + regex.lastIndex) 
    console.log(!regex.test(str) + " - " + regex.lastIndex) 
    console.log(! regex.test(str) + " - " + regex.lastIndex) 
    console.log(!regex.test(str) + " - " + regex.lastIndex) 
    console.log(! regex.test(str) + " - " + regex.lastIndex) 
})(new RegExp("new", "gmi"), "new") 

Вы увидите, что .lastIndex свойство позволяет переключаться между 0 и 3.

Я думаю, что мораль этой истории «не используйте 'g', если вы действительно не знаете, чего хотите».

+0

Спасибо, я, видимо, могу принять этот ответ через 6 минут.Теперь я понимаю, что я не понимаю модификатор 'g' и его роль в путаных, не независимых тестах регулярного выражения. –

+0

@JoeButler видит мое обновление - объект regexp предоставляет свойство «.lastIndex», которое сообщает вам, где в строке поиска он начнет следующий поиск. Вы можете явно установить это обратно к нулю, если хотите, или просто не использовать флаг «g». – Pointy

+0

Да, я не буду использовать модификатор 'g', 'global' мне кажется неинтуитивным для его функции. –

3

Я объясню вам, что происходит. Пройдите комментарии. Его в виде

regex.lastIndex, actual value, negated value 

// code below 

(function(regex, str){ 
    console.log(regex.test(str)) // 0, true, false 
    console.log(!regex.test(str)) // 3, false, true => lastIndex set to 0 
    console.log(! regex.test(str)) // 0, true, false 
    console.log(!regex.test(str)) // 3, false, true => lastIndex set to 0 
    console.log(! regex.test(str)) // 0, true, false 
})(new RegExp("new", "gmi"), "new") 

MDN

Если LastIndex равно длине строки и если регулярное выражение не совпадает с пустой строкой, то регулярное выражение не соответствует вход, и LastIndex сбрасывается в 0.

Итак, lastIndex обновляется в случае, если глобальное регулярное выражение используется более чем один раз, и он решает, где начать соответствия.

Смежные вопросы