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

170

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

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

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


В частности, этот ответ гласит, что

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

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

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


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

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

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

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

Q: мое понимание верно?


Я попробовал следующее в консоли 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 может быть какой-либо пользы.

afsantos
источник
9
Просто используйте if (data). Это мнемонический способ Javascript, чтобы проверить, dataоценивает ли переменная значение true. undefined, nullfalse, 0, пустая строка, пустой массив и (?) объект без свойств оценивается как false, остальное - true.
J0HN
20
@ J0HN - Использование if(data)будет означать, что он не может передать falseили в 0качестве значения для data.
techfoobar
@ J0HN Кроме того, тот же ответ, который я упоминаю, также утверждает, что:, if(typeof someUndefVar == whatever) -- worksи if(someUnderVar) -- error.
afsantos
2
Вероятно, должно быть data !== null && data !== undefined, что эквивалентно тому, data != nullчто эквивалентно data != undefined. Первая форма имеет тенденцию быть предпочтительной, так как она более четко описывает условия, в то время как было бы легко пропустить оба этих условия nullи undefinedпроверяться с последующими двумя условиями.
zzzzBov
2
Кстати, явные тесты для undefinedIMO - это запах кода. Это не защищенное ключевое слово null, а переменная, которая не определена. Это полностью допустимо и нарушит ваш код:undefined = 1
Izkata

Ответы:

106

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

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

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

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

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

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

Ry-
источник
32
data !== null && data !== undefinedбудет иметь смысл, хотя.
Бфаваретто
@bfavaretto: Да, так что это может быть опечатка. Но вы никогда не знаете ...: D
Ry-
1
Как я и думал, спасибо за разъяснения. Кроме того, я не думаю, что это опечатка. Я запустил поиск и подсчет во всем сценарии, и он обнаружил 10 случаев, так что ... Я думаю, что автору также необходимо разъяснить это.
afsantos
2
Вычеркните мой комментарий выше: на самом деле, data != nullпроверял бы оба nullи undefined(но, что интересно, только для nullи undefined, а не другие ложные значения).
bfavaretto
90

В 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)) {
    // ...

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

maerics
источник
5
Почему это должно выглядеть так? != nullбудет истинным для всех значений, кроме nullи undefined, и мы уверены, что эта переменная объявлена. typeofв других ситуациях это может быть даже опасно - что если вы неправильно наберете имя переменной? Это может остаться незамеченным в течение длительного времени, потому что ошибки нет.
Ry-
@maerics Итак, если бы я правильно следовал вашему ответу, в нулевой проверке, подобной описанному выше, вы бы вообще не использовали !=, только строгое сравнение !==,?
afsantos
@rynah: Я не предполагаю, что знаю достаточно об общем решении OP, чтобы знать, подходит ли нулевой тест, но я отредактировал, чтобы упомянуть тот факт, что использование «typeof» не нужно.
maerics
@afsantos: на самом деле я не думаю, что многие (любые?) значения будут преобразованы в нуль; однако рекомендуется использовать строгое сравнение ( ===), если вы действительно не знаете, что делаете и не хотите сравнивать после преобразования ( ==).
maerics
1
@Izkata: Удалите любую библиотеку, которая пытается переопределить undefined. Кроме того, Safari на iPad сделает это ни при каких условиях. Вы не можете даже delete window.undefined.
Ry-
10

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

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

если

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

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

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

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

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

Камил Келчевски
источник
8

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

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

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

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

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

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

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

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

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

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
  } 
}

источник
2

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");
}

источник
1
Хорошо, но переменная объявлена ​​в этом случае, так в чем же проблема?
Ry-
Лично я считаю foo === undefinedопасным для использования. Это делает ваш код неработоспособным для того же состояния, которое вы пытались предотвратить.
Я говорю об аргументе для рассматриваемой функции. Смотрите также мой другой комментарий .
Ry-
1
Почему это опровергается? Самое первое предложение - правильное и важное различие!
Изката
1
@Izkata: потому что нет никакого объяснения для начального утверждения. foo === undefinedвполне приемлемо в ситуации ОП (при условии, что undefinedоно не было переопределено). Ответ также не объясняет, почему !== следует использовать вместо !=.
Мэтт
1

Простой способ сделать ваш тест:

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

var b = "Volvo"; 
alert(b); //Value is Volvo

var c = null;
alert(c); //Value is null
переполнение
источник
4
Пожалуйста, добавьте некоторые объяснения относительно того, что это должно означать.
Ry-
Это не реально проверить на null.
user4642212