Обнаружение неопределенного свойства объекта - PullRequest
2613 голосов
/ 26 августа 2008

Как лучше всего проверить, не определено ли свойство объекта в JavaScript?

Ответы [ 41 ]

2495 голосов
/ 06 января 2009

Использование:

if (typeof something === "undefined") {
    alert("something is undefined");
}

Если переменная объекта имеет некоторые свойства, вы можете использовать то же самое, как это:

if (typeof my_obj.someproperties === "undefined"){
    console.log('the property is not available...'); // print into console
}
853 голосов
/ 23 августа 2010

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

Правильный код

Самый надежный способ выполнить этот тест:

if (typeof myVar === "undefined")

Это всегда будет возвращать правильный результат и даже обрабатывает ситуацию, когда myVar не объявлено.

Вырожденный код. НЕ ИСПОЛЬЗУЙТЕ.

var undefined = false;  // Shockingly, this is completely legal!
if (myVar === undefined) {
    alert("You have been misled. Run away!");
}

Кроме того, myVar === undefined вызовет ошибку в ситуации, когда myVar не объявлен.

180 голосов
/ 27 февраля 2014

Несмотря на то, что во многих других ответах яростно это рекомендую, typeof - плохой выбор . Он никогда не должен использоваться для проверки того, имеют ли переменные значение undefined, поскольку он действует как комбинированная проверка значения undefined и наличия переменной. В подавляющем большинстве случаев вы знаете, когда существует переменная, и typeof просто представит возможность тихого сбоя, если вы сделаете опечатку в имени переменной или в строковом литерале 'undefined'.

var snapshot = …;

if (typeof snaposhot === 'undefined') {
    //         ^
    // misspelled¹ – this will never run, but it won’t throw an error!
}
var foo = …;

if (typeof foo === 'undefned') {
    //                   ^
    // misspelled – this will never run, but it won’t throw an error!
}

Так что, если вы не делаете обнаружение функций², где есть неопределенность, будет ли данное имя находиться в области (например, проверка typeof module !== 'undefined' как шаг в коде, специфичном для среды CommonJS), typeof является вредным выбором при использовании для переменной, и правильный вариант - сравнить значение напрямую:

var foo = …;

if (foo === undefined) {
    ⋮
}

Некоторые распространенные заблуждения по этому поводу включают:

  • , что чтение «неинициализированной» переменной (var foo) или параметра (function bar(foo) { … }, называемого bar()) не удастся. Это просто неверно - переменные без явной инициализации и параметры, которым не были заданы значения, всегда становятся undefined и всегда находятся в области видимости.

  • , что undefined может быть перезаписано. Это намного больше. undefined не является ключевым словом в JavaScript. Вместо этого это свойство глобального объекта с неопределенным значением. Однако, начиная с ES5, это свойство было только для чтения и не конфигурируемым . Ни один современный браузер не позволяет изменять свойство undefined, и с 2017 года это происходит уже давно. Отсутствие строгого режима также не влияет на поведение undefined - оно просто заставляет операторы типа undefined = 5 ничего не делать вместо бросков. Так как это не ключевое слово, вы можете объявить переменные с именем undefined, и эти переменные можно изменить, сделав этот некогда общий шаблон:

    (function (undefined) {
        // …
    })()
    

    больше опаснее, чем использование глобального undefined. Если вам необходимо совместимость с ES3, замените undefined на void 0 - не прибегайте к typeof. (void всегда был унарным оператором, который оценивается как неопределенное значение для любого операнда.)

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

Это:

if (typeof foo.bar === 'undefined') {
    ⋮
}

равно всегда в точности эквивалентно этому³:

if (foo.bar === undefined) {
    ⋮
}

и принимая во внимание приведенный выше совет, чтобы не вводить читателей в заблуждение относительно того, почему вы используете typeof, потому что наиболее разумно использовать === для проверки на равенство, потому что это может быть реорганизовано для проверки значение переменной позже, и, поскольку она выглядит просто лучше, вы всегда должны использовать === undefined ³, а также .

Еще одна вещь, которую следует учитывать, когда дело доходит до свойств объекта, - действительно ли вы вообще хотите проверять наличие undefined. Заданное имя свойства может отсутствовать в объекте (производя значение undefined при чтении), присутствовать в самом объекте со значением undefined, присутствовать в прототипе объекта со значением undefined или присутствовать в любом из с ненулевым значением undefined. 'key' in obj скажет вам, находится ли ключ где-нибудь в цепочке прототипов объекта, а Object.prototype.hasOwnProperty.call(obj, 'key') скажет, находится ли он непосредственно на объекте. В этом ответе я не буду вдаваться в подробности о прототипах и использовании объектов в качестве карт со строковыми ключами, потому что он в основном предназначен для противодействия всем плохим советам в других ответах независимо от возможных интерпретаций исходного вопроса. Читайте о прототипах объектов на MDN , чтобы узнать больше!

¹ необычный выбор примера имени переменной? это настоящий мертвый код из расширения NoScript для Firefox.
² не думай, что не зная, что находится в области видимостиВ общем, все в порядке. Бонусная уязвимость, вызванная злоупотреблением динамической областью действия: Project Zero 1225
³ еще раз при условии, что среда ES5 + и что undefined относится к свойству undefined глобального объекта. заменить void 0 в противном случае.

146 голосов
/ 26 августа 2008

В JavaScript есть null и undefined . Они имеют разные значения.

  • undefined означает, что значение переменной не было определено; неизвестно, что это за значение.
  • null означает, что значение переменной определено и имеет значение null (не имеет значения).

Марин Хавербеке в своей бесплатной онлайн-книге « Eloquent JavaScript » (выделено мной):

Существует также аналогичное значение null, значение которого «это значение определено, но оно не имеет значения». Разница в значении между неопределенным и нулевым является в основном академической и обычно не очень интересной. В практических программах часто необходимо проверить, имеет ли что-то значение. В этих случаях может быть использовано выражение что-то == undefined, потому что, хотя они не совпадают по значению, null == undefined приведет к истине.

Итак, я думаю, что лучший способ проверить, не было ли что-то неопределенным, было бы:

if (something == undefined)

Надеюсь, это поможет!

Редактировать: В ответ на ваше редактирование свойства объекта должны работать так же.

var person = {
    name: "John",
    age: 28,
    sex: "male"
};

alert(person.name); // "John"
alert(person.fakeVariable); // undefined
114 голосов
/ 09 августа 2013

Что это значит: "неопределенное свойство объекта" ?

На самом деле это может означать две совершенно разные вещи! Во-первых, это может означать свойство, которое никогда не определялось в объекте, и, во-вторых, это может означать свойство , которое имеет неопределенное значение . Давайте посмотрим на этот код:

var o = { a: undefined }

Является ли o.a неопределенным? Да! Его значение не определено. o.b не определено? Конечно! Нет свойства 'b' вообще! Хорошо, теперь посмотрим, как разные подходы ведут себя в обеих ситуациях:

typeof o.a == 'undefined' // true
typeof o.b == 'undefined' // true
o.a === undefined // true
o.b === undefined // true
'a' in o // true
'b' in o // false

Мы ясно видим, что typeof obj.prop == 'undefined' и obj.prop === undefined эквивалентны, и они не различают эти разные ситуации. И 'prop' in obj может обнаружить ситуацию, когда свойство вообще не было определено и не обращает внимания на значение свойства, которое может быть неопределенным.

Так что же делать?

1) Вы хотите знать, является ли свойство неопределенным по первому или второму значению (наиболее типичная ситуация).

obj.prop === undefined // IMHO, see "final fight" below

2) Вы хотите просто знать, имеет ли объект какое-либо свойство и не заботиться о его значении.

'prop' in obj

Примечания:

  • Вы не можете проверить объект и его свойства одновременно. Например, это x.a === undefined или typeof x.a == 'undefined' повышает ReferenceError: x is not defined, если x не определено.
  • Переменная undefined - это глобальная переменная (так что на самом деле это window.undefined в браузерах). Он поддерживается с ECMAScript 1st Edition, а с ECMAScript 5 он только для чтения . Так что в современных браузерах это не может быть переопределено как истинное , так как многие авторы любят пугать нас, но это все еще верно для старых браузеров.

Финальный бой: obj.prop === undefined против typeof obj.prop == 'undefined'

Плюсы obj.prop === undefined:

  • Это немного короче и выглядит немного красивее
  • Движок JavaScript выдаст вам ошибку, если вы ошиблись undefined

Минусы obj.prop === undefined:

  • undefined может быть переопределено в старых браузерах

Плюсы typeof obj.prop == 'undefined':

  • Это действительно универсально! Работает в новых и старых браузерах.

Минусы typeof obj.prop == 'undefined':

  • 'undefned' ( с орфографической ошибкой ) - это просто строковая константа, поэтому движок JavaScript не сможет вам помочь, если вы ошиблись, как я только что.

Обновление (для серверного JavaScript):

Node.js поддерживает глобальную переменную undefined как global.undefined (ее также можно использовать без префикса 'global'). Я не знаю о других реализациях серверного JavaScript.

63 голосов
/ 08 июня 2011

Проблема сводится к трем случаям:

  1. У объекта есть свойство, и его значение не равно undefined.
  2. У объекта есть свойство, и его значение равно undefined.
  3. У объекта нет свойства.

Это говорит нам кое-что, что я считаю важным:

Существует разница между неопределенным членом и определенным членом с неопределенным значением.

Но, к несчастью, typeof obj.foo не говорит нам, какой из трех случаев у нас есть. Однако мы можем комбинировать это с "foo" in obj, чтобы различать случаи.

                               |  typeof obj.x === 'undefined' | !("x" in obj)
1.                     { x:1 } |  false                        | false
2.    { x : (function(){})() } |  true                         | false
3.                          {} |  true                         | true

Стоит отметить, что эти тесты одинаковы и для null записей

                               |  typeof obj.x === 'undefined' | !("x" in obj)
                    { x:null } |  false                        | false

Я бы сказал, что в некоторых случаях имеет смысл (и более понятно) проверить, присутствует ли свойство, чем проверить, не является ли оно неопределенным, и единственный случай, когда эта проверка будет отличаться, - это случай 2, редкий случай реальной записи в объекте с неопределенным значением.

Например: я только что провёл рефакторинг группы кода, которая провела несколько проверок на предмет заданного свойства объекта.

if( typeof blob.x != 'undefined' ) {  fn(blob.x); }

Что было понятнее при написании без проверки неопределенности.

if( "x" in blob ) { fn(blob.x); }

Но, как уже упоминалось, это не совсем то же самое (но более чем достаточно для моих нужд).

41 голосов
/ 27 июля 2010
if ( typeof( something ) == "undefined") 

Это сработало для меня, а остальные - нет.

37 голосов
/ 22 сентября 2010

Я не уверен, откуда пришло происхождение использования === с typeof, и как соглашение я вижу, что оно используется во многих библиотеках, но оператор typeof возвращает строковый литерал, и мы знаем, что заранее , так почему бы вам тоже захотеть это проверить?

typeof x;                      // some string literal "string", "object", "undefined"
if (typeof x === "string") {   // === is redundant because we already know typeof returns a string literal
if (typeof x == "string") {    // sufficient
22 голосов
/ 13 января 2013

Кросспостинг моего ответа на связанный вопрос Как проверить наличие "неопределенного" в JavaScript?

Специфично для этого вопроса, см. Контрольные примеры с someObject.<whatever>.


Некоторые сценарии, иллюстрирующие результаты различных ответов: 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
17 голосов
/ 12 августа 2011

Если вы делаете

if (myvar == undefined )
{ 
    alert('var does not exists or is not initialized');
}

произойдет сбой, когда переменная myvar не существует, поскольку myvar не определена, поэтому скрипт не работает, и тест не имеет никакого эффекта.

Поскольку объект окна имеет глобальную область видимости (объект по умолчанию) вне функции, объявление будет «прикреплено» к объекту окна.

Например:

var myvar = 'test';

Глобальная переменная myvar совпадает с window.myvar или window ['myvar']

Чтобы избежать ошибок при проверке существования глобальной переменной, лучше использовать:

if(window.myvar == undefined )
{ 
    alert('var does not exists or is not initialized');
}

Вопрос о том, действительно ли переменная существует, не имеет значения, ее значение неверно. В противном случае глупо инициализировать переменные с неопределенным значением, и лучше использовать значение false для инициализации. Когда вы знаете, что все объявленные вами переменные инициализируются с помощью false, вы можете просто проверить их тип или положиться на !window.myvar, чтобы проверить, имеет ли оно правильное / правильное значение. Таким образом, даже если переменная не определена, то !window.myvar одинаково для myvar = undefined или myvar = false или myvar = 0.

Когда вы ожидаете определенного типа, проверьте тип переменной. Чтобы ускорить тестирование состояния, лучше выполнить:

if( !window.myvar || typeof window.myvar != 'string' )
{
    alert('var does not exists or is not type of string');
}

Когда выполняется первое и простое условие, интерпретатор пропускает следующие тесты.

Всегда лучше использовать экземпляр / объект переменной, чтобы проверить, получило ли оно допустимое значение. Это более стабильный и лучший способ программирования.

(у)

...