Как проверить "неопределенный" в JavaScript?

Каков наиболее подходящий способ проверить, является ли переменная неопределенной в JavaScript? Я видел несколько возможных способов:

if (window.myVariable)

Или же

if (typeof(myVariable) != "undefined")

Или же

if (myVariable) //This throws an error if undefined. Should this be in Try/Catch?

16 ответов

Решение

Если вы хотите узнать, была ли переменная объявлена ​​независимо от ее значения, используйте in Оператор - самый безопасный путь. Рассмотрим этот пример.

// global scope
var theFu; // theFu has been declared, but its value is undefined
typeof theFu; // "undefined"

Но это может не быть ожидаемым результатом для некоторых случаев, так как переменная или свойство были объявлены, но просто не инициализированы. Использовать in оператор для более надежной проверки.

"theFu" in window; // true
"theFoo" in window; // false

Если вам интересно узнать, не была ли переменная объявлена ​​или имеет значение undefinedзатем используйте typeof оператор.

if (typeof myVar !== 'undefined')

typeof Оператор гарантированно возвращает строку. Прямые сравнения с undefined неприятны как undefined может быть перезаписано

window.undefined = "omg";
"omg" == undefined // true

Как отметил @CMS, это было исправлено в 5-м издании ECMAScript, и undefined не для записи.

if (window.myVar) также будет включать эти ложные значения, так что это не очень надежно:

ложный
0
""
NaN
ноль
не определено

Спасибо @CMS за указание на то, что ваш третий случай - if (myVariable) также может выдать ошибку в двух случаях. Первый, когда переменная не была определена, который бросает ReferenceError,

// abc was never declared.
if (abc) {
    // ReferenceError: abc is not defined
} 

Другой случай, когда переменная была определена, но имеет функцию-получатель, которая выдает ошибку при вызове. Например,

// or it's a property that can throw an error
Object.defineProperty(window, "myVariable", { 
    get: function() { throw new Error("W00t?"); }, 
    set: undefined 
});
if (myVariable) {
    // Error: W00t?
}

Я лично пользуюсь

myVar === undefined

Предупреждение: обратите внимание, что === используется более == и это myVar ранее был объявлен (не определен).


мне не нравится typeof myVar === "undefined", Я думаю, что это многословно и ненужно. (Я могу сделать то же самое в меньшем количестве кода.)

Теперь некоторые люди будут чувствовать боль, когда они прочитают это, крича: "Подождите! ПОДОЖДИТЕ!!! undefined можно переопределить!

Здорово. Я знаю это. Опять же, большинство переменных в Javascript могут быть переопределены. Не следует ли вам использовать какой-либо встроенный идентификатор, который можно переопределить?

Если вы следуете этому правилу, это хорошо для вас: вы не лицемер.

Дело в том, что для того, чтобы выполнять большую часть реальной работы в JS, разработчики должны полагаться на переопределяемые идентификаторы, чтобы быть тем, чем они являются. Я не слышу, чтобы люди говорили мне, что я не должен использовать setTimeout потому что кто-то может

window.setTimeout = function () {
    alert("Got you now!");
};

Итог, аргумент "это может быть переопределено", чтобы не использовать необработанный === undefined подделка

(Если вы все еще боитесь undefined будучи переопределенным, почему вы слепо интегрируете непроверенный библиотечный код в свою кодовую базу? Или даже проще: подкладочный инструмент.)


Кроме того, как typeof Подход, этот метод может "обнаружить" необъявленные переменные:

if (window.someVar === undefined) {
    doSomething();
}

Но оба эти метода просочились в свою абстракцию. Я призываю вас не использовать это или даже

if (typeof myVar !== "undefined") {
    doSomething();
}

Рассматривать:

var iAmUndefined;

Чтобы узнать, объявлена ​​эта переменная или нет, вам, возможно, придется прибегнуть к in оператор. (Во многих случаях вы можете просто прочитать код O_o).

if ("myVar" in window) {
    doSomething();
}

Но ждать! Есть еще кое-что! Что если произойдет какая-то магическая цепь прототипа? Теперь даже высший in Оператора не хватает. (Хорошо, я закончил с этой частью, за исключением того, чтобы сказать, что в 99% случаев, === undefined (и **** кашляю **** typeof) работает просто отлично. Если вас это действительно волнует, вы можете прочитать об этом самостоятельно.)

С помощью typeof это мое предпочтение. Он будет работать, когда переменная никогда не была объявлена, в отличие от любого сравнения с == или же === операторы или приведение типа с помощью if, (undefined, В отличие от null, также может быть переопределено в средах ECMAScript 3, что делает его ненадежным для сравнения, хотя почти все распространенные среды в настоящее время совместимы с ECMAScript 5 или выше).

if (typeof someUndeclaredVariable == "undefined") {
    // Works
}

if (someUndeclaredVariable === undefined) { 
    // Throws an error
}

Вам нужно использовать typeof,

if (typeof something != "undefined") {
    // ...
}

Обновление 2018-07-25

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

  • abc === undefined
  • abc === void 0
  • typeof abc == 'undefined'
  • typeof abc === 'undefined'

Даже когда я изменил тесты, чтобы Chrome не оптимизировал их, различия были незначительными. Поэтому я бы сейчас порекомендовал abc === undefined для ясности.

Соответствующее содержание от chrome://version:

  • Google Chrome: 67.0.3396.99 (официальная сборка) (64-разрядная версия) (когорта: стабильная)
  • Редакция: a337fbf3c2ab8ebc6b64b0bfdce73a20e2e2252b-refs/branch-Heads/3396@{#790}
  • ОС: Windows
  • JavaScript: V8 6.7.288.46
  • Пользовательский агент: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, как Gecko) Chrome/67.0.3396.99 Safari/537.36

Оригинальный пост 2013-11-01

В Google Chrome следующее было немного быстрее, чем typeof тестовое задание:

if (abc === void 0) {
    // Undefined
}

Разница была незначительной. Тем не менее, этот код более краткий и понятный тому, кто знает, что void 0 средства. Обратите внимание, однако, что abc все еще должен быть объявлен.

И то и другое typeof а также void были значительно быстрее, чем в сравнении с undefined, Я использовал следующий формат теста в консоли разработчика Chrome:

var abc;
start = +new Date();
for (var i = 0; i < 10000000; i++) {
    if (TEST) {
        void 1;
    }
}
end = +new Date();
end - start;

Результаты были следующими:

Test: | abc === undefined      abc === void 0      typeof abc == 'undefined'
------+---------------------------------------------------------------------
x10M  |     13678 ms               9854 ms                 9888 ms
  x1  |    1367.8 ns              985.4 ns                988.8 ns

Обратите внимание, что первая строка указывается в миллисекундах, а вторая - в наносекундах. Разница в 3,4 наносекунды - ничто. Время было довольно последовательным в последующих тестах.

Если он не определен, он не будет равен строке, содержащей символы "неопределено", так как строка не является неопределенной.

Вы можете проверить тип переменной:

if (typeof(something) != "undefined") ...

Иногда вам даже не нужно проверять тип. Если значение переменной не может иметь значение false, когда оно установлено (например, если это функция), тогда вы можете просто оценить переменную. Пример:

if (something) {
  something(param);
}
if (typeof foo == 'undefined') {
 // Do something
};

Обратите внимание, что строгое сравнение (!==) в этом случае нет необходимости, так как typeof всегда будет возвращать строку

Некоторые сценарии, иллюстрирующие результаты различных ответов: http://jsfiddle.net/drzaus/UVjM4/

(Обратите внимание, что использование var за in тесты имеют значение, когда в оболочке с ограничением объема)

Код для справки:

(function(undefined) {
    var definedButNotInitialized;
    definedAndInitialized = 3;
    someObject = {
        firstProp: "1"
        , secondProp: false
        // , undefinedProp not defined
    }
    // var notDefined;

    var tests = [
        'definedButNotInitialized in window',
        'definedAndInitialized in window',
        'someObject.firstProp in window',
        'someObject.secondProp in window',
        'someObject.undefinedProp in window',
        'notDefined in window',

        '"definedButNotInitialized" in window',
        '"definedAndInitialized" in window',
        '"someObject.firstProp" in window',
        '"someObject.secondProp" in window',
        '"someObject.undefinedProp" in window',
        '"notDefined" in window',

        'typeof definedButNotInitialized == "undefined"',
        'typeof definedButNotInitialized === typeof undefined',
        'definedButNotInitialized === undefined',
        '! definedButNotInitialized',
        '!! definedButNotInitialized',

        'typeof definedAndInitialized == "undefined"',
        'typeof definedAndInitialized === typeof undefined',
        'definedAndInitialized === undefined',
        '! definedAndInitialized',
        '!! definedAndInitialized',

        'typeof someObject.firstProp == "undefined"',
        'typeof someObject.firstProp === typeof undefined',
        'someObject.firstProp === undefined',
        '! someObject.firstProp',
        '!! someObject.firstProp',

        'typeof someObject.secondProp == "undefined"',
        'typeof someObject.secondProp === typeof undefined',
        'someObject.secondProp === undefined',
        '! someObject.secondProp',
        '!! someObject.secondProp',

        'typeof someObject.undefinedProp == "undefined"',
        'typeof someObject.undefinedProp === typeof undefined',
        'someObject.undefinedProp === undefined',
        '! someObject.undefinedProp',
        '!! someObject.undefinedProp',

        'typeof notDefined == "undefined"',
        'typeof notDefined === typeof undefined',
        'notDefined === undefined',
        '! notDefined',
        '!! notDefined'
    ];

    var output = document.getElementById('results');
    var result = '';
    for(var t in tests) {
        if( !tests.hasOwnProperty(t) ) continue; // bleh

        try {
            result = eval(tests[t]);
        } catch(ex) {
            result = 'Exception--' + ex;
        }
        console.log(tests[t], result);
        output.innerHTML += "\n" + tests[t] + ": " + result;
    }
})();

И результаты:

definedButNotInitialized in window: true
definedAndInitialized in window: false
someObject.firstProp in window: false
someObject.secondProp in window: false
someObject.undefinedProp in window: true
notDefined in window: Exception--ReferenceError: notDefined is not defined
"definedButNotInitialized" in window: false
"definedAndInitialized" in window: true
"someObject.firstProp" in window: false
"someObject.secondProp" in window: false
"someObject.undefinedProp" in window: false
"notDefined" in window: false
typeof definedButNotInitialized == "undefined": true
typeof definedButNotInitialized === typeof undefined: true
definedButNotInitialized === undefined: true
! definedButNotInitialized: true
!! definedButNotInitialized: false
typeof definedAndInitialized == "undefined": false
typeof definedAndInitialized === typeof undefined: false
definedAndInitialized === undefined: false
! definedAndInitialized: false
!! definedAndInitialized: true
typeof someObject.firstProp == "undefined": false
typeof someObject.firstProp === typeof undefined: false
someObject.firstProp === undefined: false
! someObject.firstProp: false
!! someObject.firstProp: true
typeof someObject.secondProp == "undefined": false
typeof someObject.secondProp === typeof undefined: false
someObject.secondProp === undefined: false
! someObject.secondProp: true
!! someObject.secondProp: false
typeof someObject.undefinedProp == "undefined": true
typeof someObject.undefinedProp === typeof undefined: true
someObject.undefinedProp === undefined: true
! someObject.undefinedProp: true
!! someObject.undefinedProp: false
typeof notDefined == "undefined": true
typeof notDefined === typeof undefined: true
notDefined === undefined: Exception--ReferenceError: notDefined is not defined
! notDefined: Exception--ReferenceError: notDefined is not defined
!! notDefined: Exception--ReferenceError: notDefined is not defined

В этой статье я прочитал, что фреймворки, такие как Underscore.js, используют эту функцию:

function isUndefined(obj){
    return obj === void 0;
}

Лично я всегда использую следующее:

var x;
if( x === undefined) {
    //Do something here
}
else {
   //Do something else here
}

Свойство window.undefined недоступно для записи во всех современных браузерах (JavaScript 1.8.5 или более поздней версии). Из документации Mozilla: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined я вижу следующее: одна из причин использования typeof() заключается в том, что он не выдает ошибку, если переменная не была определена.

Я предпочитаю использовать подход

x === undefined 

потому что это терпит неудачу и взрывается мне в лицо, а не тихо передает / терпит неудачу, если x не был объявлен прежде. Это предупреждает меня, что х не объявлен. Я считаю, что все переменные, используемые в JavaScript, должны быть объявлены.

Самый надежный способ проверки undefined это использовать void 0,

Это совместимо с новыми и старыми браузерами, и не может быть перезаписано как window.undefined может в некоторых случаях.

if( myVar === void 0){
    //yup it's undefined
}

Поскольку ни один из других ответов не помог мне, я предлагаю сделать это. Это сработало для меня в Internet Explorer 8:

if (typeof variable_name.value === 'undefined') {
    // variable_name is undefined
}
// x has not been defined before
if (typeof x === 'undefined') { // Evaluates to true without errors.
   // These statements execute.
}

if (x === undefined) { // Throws a ReferenceError

}

Напротив ответа @Thomas Eding:

Если я забуду объявить myVar в моем коде, тогда я получу myVar is not defined,

Давайте возьмем реальный пример:

У меня есть имя переменной, но я не уверен, объявлено ли оно где-то или нет.

Тогда ответ @Anurag поможет:

var myVariableToCheck = 'myVar';
if (window[myVariableToCheck] === undefined)
    console.log("Not declared or declared, but undefined.");

// Or you can check it directly 
if (window['myVar'] === undefined) 
    console.log("Not declared or declared, but undefined.");
    var x;
    if (x === undefined) {
        alert ("I am declared, but not defined.")
    };
    if (typeof y === "undefined") {
        alert ("I am not even declared.")
    };

    /* One more thing to understand: typeof ==='undefined' also checks 
       for if a variable is declared, but no value is assigned. In other 
       words, the variable is declared, but not defined. */

    // Will repeat above logic of x for typeof === 'undefined'
    if (x === undefined) {
        alert ("I am declared, but not defined.")
    };
    /* So typeof === 'undefined' works for both, but x === undefined 
       only works for a variable which is at least declared. */

    /* Say if I try using typeof === undefined (not in quotes) for 
       a variable which is not even declared, we will get run a 
       time error. */

    if (z === undefined) {
        alert ("I am neither declared nor defined.")
    };
    // I got this error for z ReferenceError: z is not defined 

Я использую его как параметр функции и исключаю его при выполнении функции, так что я получаю "реальное" неопределенное значение. Хотя для этого нужно поместить код внутри функции. Я нашел это во время чтения исходного кода jQuery.

undefined = 2;

(function (undefined) {
   console.log(undefined); // prints out undefined
   // and for comparison:
   if (undeclaredvar === undefined) console.log("it works!")
})()

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

Другие вопросы по тегам