题 检测未定义的对象属性


检查JavaScript中的对象属性是否未定义的最佳方法是什么?


2434
2017-08-26 07:25


起源




答案:


使用:

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

如果具有某些属性的对象变量可以使用如下所示的相同内容:

if (typeof my_obj.someproperties === "undefined"){
    console.log('the property is not available...'); // print into console
}

自ECMAScript 5以来, undefined 不能被覆盖,所以 my_obj === undefined 也会工作,但只有 my_obj 存在。这可能是也可能不是,因为你也可以使用 null 如果你需要这种语义(见 JavaScript中的null和undefined有什么区别?)。但是对于对象属性,无论属性是否存在,它都可以工作。


2321
2018-01-06 12:27



如果某个东西是null,那么它被定义(为空),但你可以将太多的检查结合起来。上面代码令人讨厌的细节是你不能定义一个函数来检查它,你可以定义函数...但尝试使用它。 - neu-rah
@ neu-rah为什么不能写一个函数?为什么不能这样的工作呢?它似乎对我有用。有没有我不考虑的情况? jsfiddle.net/djH9N/6 - Zack
@Zack你对isNullorUndefined的测试没有考虑你调用isNullOrUndefined(f)和f是未声明的情况(即没有“var f”声明的情况)。 - pnkfelix
布拉,现在有数千票。这是最糟糕的方法。我希望路人看到这个评论并决定检查...咳... 其他 答案。 - Ry-♦
你可以使用 obj !== undefined 现在。 undefined 曾经是可变的,比如 undefined = 1234 什么会导致有趣的结果。但是在Ecmascript 5之后,它不再可写了,所以我们可以使用更简单的版本。 codereadability.com/how-to-check-for-undefined-in-javascript - Bruno Buccolo


我相信这个话题有很多不正确的答案。与普遍看法相反,“未定义”是  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未声明的情况下引发错误。


805
2017-08-23 18:03



+1如果未声明myVar,则注意到myVar === undefined将引发错误 - Enrique
是的 - QUOTES显然至关重要。我的猜测是typeof函数返回一个字符串(预期的格式) - jsh
我发现这里给出的第一个理由是不使用 === undefined 扑朔迷离。是的,你可以分配给 undefined,但没有正当理由这样做,并且可以预见这样做可能会破坏您的代码。在C你可以 #define true false,在Python中,您可以分配给 True 和 False但人们并不认为有必要以这样的方式设计他们的代码,以防止他们在代码中故意破坏他们自己的环境的可能性。为什么分配的可能性 undefined 甚至值得考虑一下? - Mark Amery
除了Marks评论之外,我不明白:“myVar === undefined会在myVar未声明的情况下引发错误。” - 为什么这么糟糕?我为什么要 不 如果我引用未声明的变量,想要出错吗? - eis
在现代浏览器(FF4 +,IE9 +,Chrome未知)中,不再可能进行修改 undefined。 MDN:未定义 - Stijn


在JavaScript中有 空值 并且有 未定义。它们有不同的含义。

  • 未定义 表示尚未定义变量值;不知道它的价值是多少。
  • 空值 表示定义变量值并将其设置为null(没有值)。

Marijn Haverbeke在他的免费在线书中说:雄辩的JavaScript“(强调我的):

还有一个类似的值null,其含义是“此值已定义,但它没有值”。 undefined和null之间的意义差异主要是学术性的,通常不是很有趣。 在实际程序中,通常需要检查某些东西是否“有价值”。在这些情况下,可以使用表达式== undefined,因为即使它们不是完全相同的值,null == undefined也会产生true。

所以,我想检查某些内容是否未定义的最佳方法是:

if (something == undefined)

希望这可以帮助!

编辑: 为了响应您的编辑,对象属性应该以相同的方式工作。

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

alert(person.name); // "John"
alert(person.fakeVariable); // undefined

133
2017-08-26 07:36



if(something == undefined)更好地编写(某些东西=== undefined) - Sebastian Rittau
应该指出的是,这并非完全安全。 undefined 只是一个可以由用户重新分配的变量:写作 undefined = 'a'; 会导致您的代码不再按照您的想法执行操作。运用 typeof 更好,也适用于尚未声明的变量(不仅仅是属性)。 - Gabe Moothart
如果某个东西是未定义的全局变量,(某些东西== undefined)会出现javascript错误。 - Morgan Cheng
这个问题是,如果var a = null,那么a == undefined的计算结果为true,即使a被定义得很明确。 - Andrew
对“Eloquent Javascript”评论的这种解释是 落后。如果你真的只想检查未定义,建议的代码将不起作用(它也将检测定义的条件,但尚未确定任何值[ienull])。一个空值。建议的代码“if(something = = undefined)...”检查 都 undefined和null(没有设置值),即它被解释为“if((某事未定义)OR(某事为空))......”作者所说的是经常是你的 真 想要检查 都 undefined和null。 - Chuck Kollars


尽管在这里被许多其他答案强烈推荐, 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中的关键字。相反,它是具有Undefined值的全局对象上的属性。但是,自从ES5以来,这个属性已经存在 只读 和 非可配置。没有现代浏览器允许 undefined 物业需要更改,截至2017年,这种情况已经存在很长时间了。缺乏严格模式不会影响 undefined的行为要么 - 它只是做出陈述 undefined = 5 什么也不做,而不是扔。但是,由于它不是关键字,您可以 宣布 名称变量 undefined,这些变量可以改变,使这个曾经常见的模式:

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

    更多 比使用全局更危险 undefined。如果必须与ES3兼容,请更换 undefined 同 void 0  - 不要诉诸 typeof。 (void 一直是一元运算符,它计算任何操作数的Undefined值。)

通过变量如何解决问题,是时候解决实际问题了:对象属性。没有理由使用 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上的对象原型 更多!

¹异常选择示例变量名称?这是来自Firefox的NoScript扩展的真正死代码。
²不要以为不知道一般情况下不知道范围是什么。滥用动态范围造成的奖金漏洞: Project Zero 1225
³再次假设一个ES5 +环境 undefined 是指 undefined 全局对象的属性。替代 void 0 除此以外。


132
2018-02-26 21:17



@BenjaminGruenbaum真实但完全误导。任何非默认上下文都可以定义自己的上下文 undefined,隐藏默认值。对于大多数实际目的而言,其与覆盖它具有相同的效果。 - blgt
@blgt那是偏执的,与任何实际的东西无关。每个上下文都可以覆盖console.log,重新定义Array原型方法,甚至覆盖Function.prototype.call`挂钩,并在每次调用JavaScript函数时进行更改。保护这一点是非常偏执和相当愚蠢的。就像我(和minitech)说的那样,你可以使用 void 0 比较未定义,但再次 - 这是愚蠢和矫枉过正。 - Benjamin Gruenbaum
我希望我有一个以上的支持。这是最正确的答案。我真的想停止看 typeof something === "undefined")  在代码中。 - Simon Baumgardt-Wellander
@BenjaminGruenbaum对于懒惰的程序员, void 0 是(一次)都短 和 更安全!这是我书中的一个胜利。 - wizzwizz4


这是什么意思: “未定义的对象属性”

实际上它可能意味着两件完全不同的东西!首先,它可以意味着 从未定义过的属性 在对象中,第二,它可以意味着 具有未定义值的属性。我们来看看这段代码:

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第1版以来一直受到支持,自ECMAScript 5以来一直受到支持 只读。所以在现代浏览器中它不可能 重新定义为真 正如许多作者喜欢吓唬我们一样,但对于旧浏览器来说,这仍然是正确的。

最后的战斗: obj.prop === undefined VS 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 (它也可以在没有'全局'前缀的情况下使用)。我不知道服务器端JavaScript的其他实现。


101
2017-08-08 20:28



@Bergi感谢您的评论。我纠正了我的答案。在我的辩护中,我可以说当前(截至v.10.10.18) 官方Node.js文档 什么也没说 undefined 作为成员 global。也没有 console.log(global); 也不 for (var key in global) { ... } 没有显示 未定义 作为成员 全球。但测试就好 'undefined' in global 显示相反的情况。 - Konstantin Smolyanin
从那以后它不需要额外的文档 它是在EcmaScript规范中,也说 [[Enumerable]] 是假的:-) - Bergi
关于 Minuses of typeof obj.prop == 'undefined'这可以通过写作来避免 typeof obj.prop == typeof undefined。这也给出了非常好的对称性。 - hlovdal
@hlovdal:这完全没有意义 obj.prop === undefined。 - Ry-♦
当我们对问题标题如实 “检测 未定义的属性“你不回答,不是第一句中的(不同的,更容易的)问题(“检查是否未定义......”) if ('foo' in o)...你的回答确实是这里的第一个正确答案。几乎所有人都回答了这句话。 - Frank Nocke


问题可归结为三种情况:

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

但正如已经提到的,这些并不完全相同(但对我的需求来说已经足够好了)。


59
2018-06-08 04:04



嗨迈克尔。伟大的建议,我认为它确实使事情更清洁。然而,我发现的一个问题是使用时!运算符“in”。你不得不说 if (!("x" in blob)) {} 用括号括起来,因为!运算符优先于'in'。希望能帮助别人。 - Simon East
对不起迈克尔,但根据最初的问题,这是不正确的,或者至少是误导性的。 'in'不足以测试对象属性是否具有未定义的类型。为了证明,请看这个小提琴: jsfiddle.net/CsLKJ/4 - Tex
这两个代码部分做了不同的事情!考虑并给出对象 a = {b: undefined};然后 typeof a.b === typeof a.c === 'undefined' 但 'b' in a 和 !('c' in a)。 - mgol
+1。 OP并未明确该财产是否存在且具有价值 未定义,或者属性本身是否未定义(即不存在)。 - RobG
我建议你在第一张表中更改点(2.) { x : undefined } 或者至少将其作为表中(2)的另一种选择 - 我不得不考虑一下,意识到这一点(2.)评估为 undefined(虽然你稍后提到)。 - mucaho


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

这对我有用,而其他人没有。


38
2017-07-27 16:03



由于typeof是运营商,所以不需要支付 - aehlke
但是他们更清楚地检查了什么。否则可能会被视为 typeof (something == "undefined")。 - Abhi Beckert
如果你需要括号,那么你应该学习JS中的运算符优先级: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - Ian
括号之所以有用,正是因为您不需要在JS中学习运算符优先级,也不需要推测未来的维护程序员是否需要在JS中学习运算符优先级。 - DaveWalley
括号有助于澄清事物。但在这种情况下,它们只是使运算符看起来像一个函数。毫无疑问,这澄清了程序员的意图。但是如果你不确定运算符优先级,你应该把它写成 (typeof something) === "undefined"。 - Robert


我不确定使用的来源 === 同 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

33
2017-09-22 14:20



伟大的点埃里克。检查类型是否也会影响性能? - Simon East
@Simon:恰恰相反 - 人们可以预期在'==='案件中避免强制行为可以轻微打击。快速而肮脏的测试显示,在FF5.0.1下,“===”比“==”快5% - Antony Hatchkins
更全面的测试表明,在FF下,IE和Chrome'=='或多或少比'==='(5-10%)更快,而Opera根本没有任何差别: jsperf.com/triple-equals-vs-twice-equals/6 - Antony Hatchkins
运用 == 仍然需要 至少 类型检查 - 解释器无法在不知道其类型的情况下比较两个操作数。 - Alnitak
== 是一个少于一个字符 === :) - svidgen


交叉我的 回答 来自相关问题 如何在JavaScript中检查“undefined”?

具体到这个问题,请参阅测试用例 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

19
2018-01-13 17:43





如果你这样做

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

变量时它会失败 myvar 不存在,因为未定义myvar,因此脚本被破坏且测试无效。

由于窗口对象在函数外部具有全局范围(默认对象),因此声明将“附加”到窗口对象。

例如:

var myvar = 'test';

全局变量 MYVAR 是相同的 window.myvar 要么 窗口[ 'MYVAR']

为避免在存在全局变量时测试错误,最好使用:

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

变量确实存在的问题无关紧要,其值不正确。否则,使用undefined初始化变量是愚蠢的,最好使用值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');
}

当第一个和简单条件为真时,解释器会跳过下一个测试。

最好使用变量的实例/对象来检查它是否具有有效值。它更稳定,是一种更好的编程方式。

(y)的


14
2017-08-12 14:40