如何检查JavaScript中的对象属性是否未定义?


当前回答

我没有看到(希望我没有错过)任何人在物业前检查该对象。因此,这是最短和最有效的(虽然不一定是最清楚的):

if (obj && obj.prop) {
  // Do something;
}

如果obj或obj.prop为undefined、null或“falsy”,If语句将不执行代码块。这通常是大多数代码块语句(在JavaScript中)所需的行为。

更新:(2021 7月2日)

最新版本的JavaScript为可选链接:?。

这可能是检查对象财产是否存在的最明确、最有效的方法。

裁判:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

其他回答

交叉发布我对相关问题的回答如何在JavaScript中检查“undefined”?。

具体到这个问题,请参阅someObject的测试用例<无论什么>。


说明各种答案结果的一些场景:http://jsfiddle.net/drzaus/UVjM4/

(请注意,在测试中使用var会在作用域包装器中产生差异)

参考代码:

(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

这里的许多答案都强烈推荐typeof,但typeof是一个糟糕的选择。它不应用于检查变量是否具有未定义的值,因为它充当了未定义值和变量是否存在的组合检查。在绝大多数情况下,您知道变量何时存在,如果您在变量名称或字符串文字“undefined”中键入了错误,typeof可能会导致无声失败。

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) {
    ⋮
}

对此,一些常见的误解包括:

读取“未初始化”变量(varfoo)或参数(函数栏(foo){…},称为bar())将失败。这根本不是真的——没有显式初始化的变量和没有给定值的参数总是未定义,并且总是在范围内。可以覆盖未定义的。的确,undefined不是关键字,但它是只读的,不可配置。尽管有其他内置程序的非关键字状态(Object、Math、NaN…),但您可能无法避免它们,而且实用代码通常不是在主动恶意环境中编写的,因此这不是担心未定义的好理由。(但如果您正在编写代码生成器,请随意使用void 0。)

随着变量如何发挥作用,是时候解决实际问题了:对象财产。没有理由对对象财产使用typeof。早期关于特征检测的例外在这里不适用–typeof只对变量有特殊行为,引用对象财产的表达式不是变量。

这:

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

始终完全等于此³:

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

考虑到上面的建议,避免让读者混淆为什么要使用typeof,因为使用==来检查等式是最有意义的,因为稍后可以将其重构为检查变量的值,并且因为它看起来更简单,所以在这里也应该始终使用==undefined³。

当涉及到对象财产时,需要考虑的另一件事是您是否真的想检查未定义的属性。给定的属性名称可以在对象上不存在(读取时产生未定义的值),可以在对象本身上出现,但值未定义,可以在该对象的原型上出现,值未定义或出现在其中一个值未定义的对象上obj中的“key”将告诉您键是否位于对象原型链上的任何位置,而object.protype.hasOwnProperty.call(obj,“key”)将告诉您它是否直接位于对象上。不过,我不会在这个答案中详细讨论原型和使用对象作为字符串键映射,因为它主要是为了应对其他答案中的所有坏建议,而不管对原始问题的可能解释。阅读MDN上的对象原型了解更多信息!

¹不寻常的变量名称示例选择?这是Firefox的NoScript扩展中真正的死代码。²但是,不要认为不知道范围内的内容是可以的。滥用动态范围导致的奖金漏洞:项目零1225再次假设ES5+环境,undefined指的是全局对象的未定义属性。

使用动态变量的版本你知道吗?

var boo='Ala';函数检查(){if(this['fo']){console.log('o is here');}其他{console.log('没有foo');}如果(这个['bo']){console.log('boo在这里');}其他{console.log('没有boo');}}check();

所有答案都不完整。这是了解存在“定义为未定义”属性的正确方法:

var hasUndefinedProperty = function hasUndefinedProperty(obj, prop){
  return ((prop in obj) && (typeof obj[prop] == 'undefined'));
};

例子:

var a = { b : 1, e : null };
a.c = a.d;

hasUndefinedProperty(a, 'b'); // false: b is defined as 1
hasUndefinedProperty(a, 'c'); // true: c is defined as undefined
hasUndefinedProperty(a, 'd'); // false: d is undefined
hasUndefinedProperty(a, 'e'); // false: e is defined as null

// And now...
delete a.c ;
hasUndefinedProperty(a, 'c'); // false: c is undefined

遗憾的是,这是正确的答案,却被错误的答案所掩盖>_<

所以,对于任何路过的人,我会免费给你未定义的!!

var undefined ; undefined ; // undefined
({}).a ;                    // undefined
[].a ;                      // undefined
''.a ;                      // undefined
(function(){}()) ;          // undefined
void(0) ;                   // undefined
eval() ;                    // undefined
1..a ;                      // undefined
/a/.a ;                     // undefined
(true).a ;                  // undefined

如果定义了一个新变量,可以用一种优雅的方式将已定义的属性分配给它;如果未定义,则可以将默认值分配给它作为回退。

var a = obj.prop || defaultValue;

如果您有一个函数,它会接收一个额外的配置属性,那么这是合适的:

var yourFunction = function(config){

   this.config = config || {};
   this.yourConfigValue = config.yourConfigValue || 1;
   console.log(this.yourConfigValue);
}

正在执行

yourFunction({yourConfigValue:2});
//=> 2

yourFunction();
//=> 1

yourFunction({otherProperty:5});
//=> 1