Detecting an undefined object property

后端 未结 30 2940
花落未央
花落未央 2020-11-21 04:43

What\'s the best way of checking if an object property in JavaScript is undefined?

30条回答
  •  旧巷少年郎
    2020-11-21 05:27

    Despite being vehemently recommended by many other answers here, typeof is a bad choice. It should never be used for checking whether variables have the value undefined, because it acts as a combined check for the value undefined and for whether a variable exists. In the vast majority of cases, you know when a variable exists, and typeof will just introduce the potential for a silent failure if you make a typo in the variable name or in the string literal '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!
    }
    

    So unless you’re doing feature detection², where there’s uncertainty whether a given name will be in scope (like checking typeof module !== 'undefined' as a step in code specific to a CommonJS environment), typeof is a harmful choice when used on a variable, and the correct option is to compare the value directly:

    var foo = …;
    
    if (foo === undefined) {
        ⋮
    }
    

    Some common misconceptions about this include:

    • that reading an “uninitialized” variable (var foo) or parameter (function bar(foo) { … }, called as bar()) will fail. This is simply not true – variables without explicit initialization and parameters that weren’t given values always become undefined, and are always in scope.

    • that undefined can be overwritten. It’s true that undefined isn’t a keyword, but it is read-only and non-configurable. There are other built-ins you probably don’t avoid despite their non-keyword status (Object, Math, NaN…) and practical code usually isn’t written in an actively malicious environment, so this isn’t a good reason to be worried about undefined. (But if you are writing a code generator, feel free to use void 0.)

    With how variables work out of the way, it’s time to address the actual question: object properties. There is no reason to ever use typeof for object properties. The earlier exception regarding feature detection doesn’t apply here – typeof only has special behaviour on variables, and expressions that reference object properties are not variables.

    This:

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

    is always exactly equivalent to this³:

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

    and taking into account the advice above, to avoid confusing readers as to why you’re using typeof, because it makes the most sense to use === to check for equality, because it could be refactored to checking a variable’s value later, and because it just plain looks better, you should always use === undefined³ here as well.

    Something else to consider when it comes to object properties is whether you really want to check for undefined at all. A given property name can be absent on an object (producing the value undefined when read), present on the object itself with the value undefined, present on the object’s prototype with the value undefined, or present on either of those with a non-undefined value. 'key' in obj will tell you whether a key is anywhere on an object’s prototype chain, and Object.prototype.hasOwnProperty.call(obj, 'key') will tell you whether it’s directly on the object. I won’t go into detail in this answer about prototypes and using objects as string-keyed maps, though, because it’s mostly intended to counter all the bad advice in other answers irrespective of the possible interpretations of the original question. Read up on object prototypes on MDN for more!

    ¹ unusual choice of example variable name? this is real dead code from the NoScript extension for Firefox.
    ² don’t assume that not knowing what’s in scope is okay in general, though. bonus vulnerability caused by abuse of dynamic scope: Project Zero 1225
    ³ once again assuming an ES5+ environment and that undefined refers to the undefined property of the global object.

提交回复
热议问题