Как использовать экзистенциальный оператор CoffeeScript, чтобы проверить некоторые свойства объекта на неопределенность? - PullRequest
25 голосов
/ 03 апреля 2012

Я хотел бы использовать экзистенциальный оператор CoffeeScript, чтобы проверить некоторые свойства объекта на неопределенность. Однако я столкнулся с небольшой проблемой.

Код такой:

console.log test if test?

Компилируется в:

if (typeof test !== "undefined" && test !== null) console.log(test);

Какое поведение я хотел бы увидеть. Тем не менее, когда я пытаюсь использовать его в отношении свойств объекта, например:

console.log test.test if test.test?

Я получаю что-то вроде этого:

if (test.test != null) console.log(test.test);

Который вообще не выглядит как проверка на undefined. Единственный способ, которым я мог бы добиться такого же (1: 1) поведения, как и при использовании его для объектов, - использовать большую проверку:

console.log test.test if typeof test.test != "undefined" and test.test != null

Вопрос - я что-то не так делаю? Или скомпилированный код является достаточным для проверки существования свойства (нулевая проверка с преобразованием типов)?

Ответы [ 3 ]

51 голосов
/ 03 апреля 2012

Это обычная путаница с экзистенциальным оператором: иногда

x?

компилируется в

typeof test !== "undefined" && test !== null

и в других случаях он просто компилируется в

x != null

Эти два значения эквивалентны , поскольку x != null будет false, если x равно null или undefined. Так что x != null - это более компактный способ выражения (x !== undefined && x !== null). Причина, по которой происходит компиляция typeof, заключается в том, что компилятор считает, что x, возможно, вообще не был определен, и в этом случае выполнение теста на равенство вызовет ReferenceError: x is not defined.

В вашем конкретном случае test.test может иметь значение undefined, но вы не можете получить ReferenceError, ссылаясь на неопределенное свойство существующего объекта, поэтому компилятор выбирает более короткий вывод.

20 голосов
/ 16 ноября 2013

Этот JavaScript:

a.foo != null

фактически проверяет, является ли свойство foo a ни undefined, ни null. Обратите внимание, что a.foo? переведено на JavaScript, который использует != null вместо !== null. Преобразования, которые != делает, означают, что оба они истинны:

null == null
undefined == null

Простой a? становится таким JavaScript:

typeof a !== "undefined" && a !== null

потому что есть три условия для проверки:

  1. Есть ли где-нибудь область действия a? 1023 *
  2. Имеет ли a значение undefined?
  3. Имеет ли a значение null?

Первое условие важно, поскольку просто сказать, что a != null вызовет ReferenceError, если в области действия нет a, а сказать, что typeof a === 'undefined' не будет. Проверка typeof также учитывает условие a === undefined в 2 . Затем мы можем завершить его строгим тестом a !== null, поскольку он учитывает 3 без потери производительности из-за ненужных != (примечание: != и == медленнее, чем !== и === из-за неявных преобразований).

Небольшое чтение о том, что != и !== делают, может быть плодотворным:

MDN: операторы сравнения


Что касается вашего комментария к удаленному ответу, if(a.foo) - это совершенно правильный синтаксис , если , вы завершите оператор if:

if(a.foo)
    do_interesting_things()
# or
do_interesting_things() if(a.foo)

Однако if(a.foo) и if(a.foo?) отличаются тем, как они обрабатывают 0, false и ''.

4 голосов
/ 03 апреля 2012

Дикая догадка; Вы пробовали console.log test.test if test?.test??

Только что протестировал его с coffee -p -e 'console.log test.test if test?.test?', который компилируется в:

(функция () {

if ((typeof test! == "undefined" && test! == null? Test.test: void 0)! = Ноль) { console.log (test.test); } * +1010 * .

}) вызова (это);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...