Проверка нуля JavaScript

Я наткнулся на следующий код:

function test(data) {
    if (data != null && data !== undefined) {
        // some code here
    }
}

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


In particular, this answer states that

Вы получите сообщение об ошибке, если получите доступ к неопределенной переменной в любом контексте, кроме typeof.

Обновление: приведенный выше ответ (цитата) может вводить в заблуждение. В нем должно быть написано «необъявленная переменная» вместо «неопределенная переменная».

Как я выяснил, в ответах Райана ♦, maerics и nwellnhof, даже если функции не предоставлены аргументы, всегда объявляются ее переменные для аргументов. Этот факт также подтверждает ошибочность первого пункта в списке ниже.


Насколько я понимаю, возможны следующие сценарии:

  • Функция была вызвана без аргументов, что сделало data неопределенной переменной и вызвало ошибку на data != null.

  • Функция была вызвана специально с null (или undefined) в качестве аргумента, и в этом случае data != null уже защищает внутренний код, делая && data !== undefined бесполезным.

  • Функция была вызвана с ненулевым аргументом, и в этом случае она тривиально передаст и data != null , и data !== undefined.

В: Я правильно понимаю?


Я пробовал в консоли Firefox следующее:

--
[15:31:31.057] false != null
[15:31:31.061] true
--
[15:31:37.985] false !== undefined
[15:31:37.989] true
--
[15:32:59.934] null != null
[15:32:59.937] false
--
[15:33:05.221] undefined != null
[15:33:05.225] false
--
[15:35:12.231] "" != null
[15:35:12.235] true
--
[15:35:19.214] "" !== undefined
[15:35:19.218] true

Я не могу понять, в каком случае data !== undefined после data != null может оказаться полезным.


person afsantos    schedule 21.05.2013    source источник
comment
Просто используйте if (data). Это мнемонический способ Javascript проверить, истинна ли переменная data. undefined, null, false, 0, пустая строка, пустой массив и (?) Объект без свойств оценивается как false, остальное истинно.   -  person J0HN    schedule 21.05.2013
comment
@ J0HN - Использование if(data) означало бы, что он не может передавать false или 0 в качестве значений для data.   -  person techfoobar    schedule 21.05.2013
comment
@ J0HN Кроме того, в том же ответе, который я упоминал, также говорится, что: if(typeof someUndefVar == whatever) -- works и if(someUnderVar) -- error.   -  person afsantos    schedule 21.05.2013
comment
Вероятно, это должно быть data !== null && data !== undefined, что эквивалентно data != null, что эквивалентно data != undefined. Первая форма, как правило, предпочтительнее, поскольку она более четко описывает условия, тогда как было бы легко упустить из виду, что и null, и undefined проверяются с двумя последними условиями.   -  person zzzzBov    schedule 21.05.2013
comment
Кстати, явные тесты для undefined - это ИМО запах кода. Это не защищенное ключевое слово, такое как null, это переменная, которая не определена. Это полностью верно и нарушит ваш код: undefined = 1   -  person Izkata    schedule 21.05.2013
comment
@Izkata Я читал здесь в другой раз, что не следует слишком сильно путаться с undefined, так как он действительно может быть определен, как вы указываете. С тех пор я стараюсь избегать упоминания undefined где-либо в моем коде, а при необходимости просто использую typeof или == null.   -  person afsantos    schedule 21.05.2013
comment
Незначительное раздражение: это мнемонический Javascript, должно быть, это идиоматический Javascript.   -  person Marc Bollinger    schedule 18.08.2014
comment
@ J0HN Boolean({}) и Boolean([]) верны.   -  person Jim Jones    schedule 18.07.2015


Ответы (8)


«Неопределенная переменная» отличается от значения undefined.

Неопределенная переменная:

var a;
alert(b); // ReferenceError: b is not defined

Переменная со значением undefined:

var a;
alert(a); // Alerts “undefined”

Когда функция принимает аргумент, этот аргумент всегда объявляется, даже если его значение равно undefined, и поэтому ошибок не будет. Вы правы насчет того, что != null, а затем !== undefined бесполезны.

person Ry-♦    schedule 21.05.2013
comment
Однако data !== null && data !== undefined имеет смысл. - person bfavaretto; 21.05.2013
comment
@bfavaretto: Ага, так что это может быть опечатка. Но мало ли…: D - person Ry-♦; 21.05.2013
comment
Как я и думал, спасибо за разъяснения. Также я не считаю это опечаткой. Я выполнил find-and-count во всем скрипте, и он обнаружил 10 вхождений, так что ... Думаю, автору также нужно пояснение по этому поводу. - person afsantos; 21.05.2013
comment
Поцарапайте мой комментарий выше: на самом деле data != null будет проверять и null, и undefined (но, что интересно, только null и undefined, а не другие ложные значения). - person bfavaretto; 22.05.2013

В JavaScript null - это специальный одноэлементный объект, который полезен для сигнализации «нет значения». Вы можете проверить это путем сравнения, и, как обычно в JavaScript, рекомендуется использовать оператор ===, чтобы избежать путаницы при приведении типов:

var a = null;
alert(a === null); // true

Как упоминает @rynah, "undefined" в JavaScript немного сбивает с толку. Однако всегда безопасно проверить, является ли typeof(x) строкой «undefined», даже если «x» не является объявленной переменной:

alert(typeof(x) === 'undefined'); // true

Также переменные могут иметь «неопределенное значение», если они не инициализированы:

var y;
alert(typeof(y) === 'undefined'); // true

Собирая все вместе, ваш чек должен выглядеть так:

if ((typeof(data) !== 'undefined') && (data !== null)) {
  // ...

Однако, поскольку переменная «data» всегда определяется, поскольку она является формальным параметром функции, использование оператора «typeof» не требуется, и вы можете безопасно сравнивать напрямую с «неопределенным значением».

function(data) {
  if ((data !== undefined) && (data !== null)) {
    // ...

Этот фрагмент сводится к тому, что «если функция была вызвана с аргументом, который определен и не является нулевым ...»

person maerics    schedule 21.05.2013
comment
Но почему должно это выглядеть именно так? != null будет истинным для всех значений, кроме null и undefined, и мы уверены, что эта переменная объявлена. typeof в других ситуациях может быть даже опасным - что, если вы неправильно введете имя переменной? Это может оставаться незамеченным в течение долгого времени, потому что ошибок нет. - person Ry-♦; 21.05.2013
comment
@maerics Итак, если я правильно следил за вашим ответом, при нулевой проверке, как в приведенном выше сценарии, вы бы вообще не использовали !=, а только строгое сравнение, !==? - person afsantos; 21.05.2013
comment
@rynah: Я не предполагаю, что знаю достаточно об общем решении OP, чтобы знать, подходит ли нулевой тест или нет, но я отредактировал, чтобы упомянуть тот факт, что использование typeof не нужно. - person maerics; 21.05.2013
comment
@afsantos: на самом деле я не думаю, что многие (любые?) значения будут преобразованы в null; однако рекомендуется использовать строгое сравнение (===), если вы действительно не знаете, что делаете, и не хотите сравнения после преобразования (==). - person maerics; 21.05.2013
comment
@maerics Конечно, я согласен с этим. В качестве дополнительного пояснения я провел больше тестов в консоли. Единственные значения, которые, кажется, преобразуются в null, - это undefined и null. Запуск undefined == null дает true. - person afsantos; 21.05.2013
comment
+1 полностью за typeof(data) !== "undefined", который не попадает в ловушку undefined = 1 - person Izkata; 21.05.2013
comment
@Izkata: Эта ловушка применима только в том случае, если вы используете Internet Explorer 8 или более ранней версии для разработки, используете условные выражения Yoda и все время используете свободное равенство. Это редкое сочетание. - person Ry-♦; 22.05.2013
comment
@rynah Нам все еще нужно поддерживать IE6 для наших клиентов, это стало известно как ловушка, потому что одно время им злоупотребляли в библиотеке JS, а Safari на iPad выдает исключения javascript в определенных ситуациях, связанных с тем, что он не является ключевым словом: undefined is undefined . В общем, я все еще говорю, не надейтесь на это. - person Izkata; 22.05.2013
comment
@Izkata: Отбросьте любую библиотеку, которая пытается переопределить undefined. Кроме того, Safari на iPad этого не сделает ни при каких обстоятельствах. Ты не можешь даже delete window.undefined. - person Ry-♦; 22.05.2013

В вашем случае используйте data==null (что верно ТОЛЬКО для null и undefined - на втором изображении фокус на строках / столбцах null-undefined)

function test(data) {
    if (data != null) {
        console.log('Data: ', data);
    }
}

test();          // the data=undefined
test(null);      // the data=null
test(undefined); // the data=undefined

test(0); 
test(false); 
test('something');

Здесь у вас есть все (src):

если

введите описание изображения здесь

== (его отрицание ! =)

введите описание изображения здесь

=== (его отрицание ! ==)

введите описание изображения здесь

person Kamil Kiełczewski    schedule 24.04.2019

В: Функция была вызвана без аргументов, что сделало данные неопределенной переменной и вызвало ошибку при data! = null.

A: Да, data будет установлено значение undefined. См. раздел 10.5 Создание экземпляра привязки объявления спецификации. Но доступ к неопределенному значению не вызывает ошибки. Вы, вероятно, путаете это с доступом к необъявленной переменной в строгом режиме, который вызывает ошибку.

В: Функция была вызвана специально с null (или undefined) в качестве аргумента, и в этом случае data! = null уже защищает внутренний код, делая && data! == undefined бесполезным.

В: Функция была вызвана с ненулевым аргументом, и в этом случае она тривиально передаст и data! = null, и data! == undefined.

A: Верно. Обратите внимание, что следующие тесты эквивалентны:

data != null
data != undefined
data !== null && data !== undefined

См. раздел 11.9.3 «Абстрактный алгоритм сравнения равенства» и section 11.9.6 Алгоритм строгого сравнения равенства спецификации.

person nwellnhof    schedule 21.05.2013
comment
Меня не путали необъявленные переменные, я действительно не знал, как это работает, когда не было предоставлено никаких аргументов. Я был убежден, что data вообще не будет существовать, вместо того, чтобы быть установленным на undefined. Я ценю разъяснения, и эти ссылки помогли мне лучше понять, как работают оба равенства. - person afsantos; 21.05.2013

typeof foo === "undefined" отличается от foo === undefined, никогда не путайте их. typeof foo === "undefined" - это то, что вам действительно нужно. Также используйте !== вместо !=

Таким образом, заявление можно записать как

function (data) {
  if (typeof data !== "undefined" && data !== null) {
    // some code here
  }
}

Изменить:

Вы не можете использовать foo === undefined для необъявленных переменных.

var t1;

if(typeof t1 === "undefined")
{
  alert("cp1");
}

if(t1 === undefined)
{
  alert("cp2");
}

if(typeof t2 === "undefined")
{
  alert("cp3");
}

if(t2 === undefined) // fails as t2 is never declared
{
  alert("cp4");
}
person Community    schedule 21.05.2013
comment
Хорошо, но в этом случае переменная объявлена, так в чем проблема? - person Ry-♦; 21.05.2013
comment
Лично я считаю foo === undefined опасным в использовании. Это приводит к тому, что ваш код не работает при том же состоянии, которое вы пытались предотвратить. - person ; 21.05.2013
comment
Я говорю об аргументе рассматриваемой функции. См. Также мой другой комментарий. - person Ry-♦; 21.05.2013
comment
Почему за это отказывают‽ Самое первое предложение - правильное и важное различие! - person Izkata; 21.05.2013
comment
@Izkata: потому что нет объяснения первоначальному утверждению. foo === undefined вполне приемлемо в ситуации OP (при условии, что undefined не был отменен). Ответ также не может объяснить почему !== следует использовать вместо !=. - person Matt; 21.05.2013

Я думаю, что тестирование переменных для значений, которых вы не ожидаете, в целом не является хорошей идеей. Потому что тест как свой можно рассматривать как написание черного списка запрещенных значений. Но что, если вы забудете перечислить все запрещенные значения? Кто-то, даже вы, может взломать ваш код, передав неожиданное значение. Поэтому более подходящим подходом является что-то вроде белого списка - проверка переменных только на ожидаемые значения, а не на неожиданные. Например, если вы ожидаете, что значение данных будет строкой, вместо этого:

function (data) {
  if (data != null && data !== undefined) {
    // some code here
    // but what if data === false?
    // or data === '' - empty string?
  }
}

сделай что-нибудь вроде этого:

function (data) {
  if (typeof data === 'string' && data.length) {
    // consume string here, it is here for sure
    // cleaner, it is obvious what type you expect
    // safer, less error prone due to implicit coercion
  } 
}
person Community    schedule 10.12.2017

Самый простой способ провести тест:

function (data) {
    if (data) { // check if null, undefined, empty ...
        // some code here
    }
}
person Kadiri    schedule 21.05.2013
comment
Разве этот тест не зависит от контекста? Я имею в виду, что если ожидаемый тип для data является строкой, этот тест возвращает false для пустых строк, что может или не может быть подходящим (функция может захотеть каким-то образом обработать пустую строку). - person afsantos; 21.05.2013
comment
За исключением того, что если данные имеют значение "", 0 или NaN (или другие), блок if будет пропущен; что может быть или не быть намерением OP. - person maerics; 21.05.2013
comment
Извините @afsantos, я не видел вашего комментария, если вы хотите получить false, когда данные не определены, null ... кроме случаев, когда дата пуста, вам нужно создать другой var toTest = data; с другим тестом после первого, например: if (toTest ==) {// здесь какой-то код} - person Kadiri; 22.05.2013

person    schedule
comment
Пожалуйста, поясните, что это должно означать. - person Ry-♦; 31.08.2014
comment
На самом деле это не проверка на null. - person Sebastian Simon; 07.06.2016