检测未定义的对象属性


Answers:


2678

检查属性值是否为特殊值的通常方法undefined是:

if(o.myProperty === undefined) {
  alert("myProperty value is the special value `undefined`");
}

要检查对象是否实际上没有这样的属性,并因此undefined在尝试访问它时默认情况下将返回:

if(!o.hasOwnProperty('myProperty')) {
  alert("myProperty does not exist");
}

检查与标识符关联的值是否为特殊值undefined或者是否尚未声明该标识符。注意:此方法是引用未声明(但值不同于undefined)标识符的唯一方法,且不会出现早期错误:

if(typeof myVariable === 'undefined') {
  alert('myVariable is either the special value `undefined`, or it has not been declared');
}

在ECMAScript 5之前的JavaScript版本中,全局对象上名为“ undefined”的属性是可写的,因此,foo === undefined如果不小心重新定义了一个简单的检查,它的行为可能会出乎意料。在现代JavaScript中,该属性为只读。

但是,在现代JavaScript中,“未定义”不是关键字,因此函数内的变量可以命名为“未定义”并隐藏全局属性。

如果您担心这种(不太可能)边缘情况,则可以使用void运算符获取特殊undefined值本身:

if(myVariable === void 0) {
  alert("myVariable is the special value `undefined`");
}

9
如果某项为null,则将其定义为(null),但是您可以将too检验进行共轭。上面代码令人讨厌的细节是您无法定义一个函数来检查它,也可以定义该函数...但是请尝试使用它。
neu-rah 2012年

5
@ neu-rah为什么不能编写函数?为什么这样的东西不起作用?它似乎为我工作。我有没有考虑的情况?jsfiddle.net/djH9N/6
Zack

7
@Zack您对isNullorUndefined的测试未考虑调用isNullOrUndefined(f)且未声明f的情况(即没有“ var f”声明的情况)。
pnkfelix 2013年

109
布拉,现在有数千票。这是最糟糕的方法。我希望路人看到此评论并决定检查...嗯... 其他答案。
Ry-

17
obj !== undefined现在就可以使用。undefined过去是易变的,就像undefined = 1234会引起有趣结果的东西。但是在Ecmascript 5之后,它不再可写,因此我们可以使用更简单的版本。codereadability.com/how-to-check-for-undefined-in-javascript
布鲁诺Buccolo

899

我相信对此主题有许多不正确的答案。与通常的看法相反,“未定义” 不是 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的情况下将引发错误。


133
+1表示myVar === undefined如果未声明myVar将引发错误
Enrique

73
我发现这里给出的第一个理由是不使用=== undefined困惑。是的,您可以分配给undefined,但是没有正当理由这样做,并且可以预料这样做可能会破坏您的代码。在C中可以#define true false,在Python中可以分配给TrueFalse,但是人们并不认为需要用那些语言来设计代码,以防止自己故意在代码中的其他地方破坏自己的环境。 。为什么分配给undefined这里的可能性值得考虑?
Mark Amery 2013年

19
除了Marks注释之外,我不明白这一点:“ myVar === undefined将在未声明myVar的情况下引发错误。” -为什么这不好?如果引用未声明的变量,为什么希望出错?
2013年

5
另外请记住,您始终void 0可以获取undefined指向的价值。这样就可以了if (myVar === void 0)。在0没有特别的,你可以随便把任何表达中。
Claudiu

28
在现代浏览器(FF4 +,IE9 +,Chrome未知)中,无法再进行修改undefinedMDN:未定义
user247702 2014年

228

尽管这里有许多其他答案强烈建议,但这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什么都不做,而不是抛出。但是,由于它不是关键字,因此可以使用name 声明变量undefined,并且可以更改这些变量,从而形成以下常见的模式:

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

    比使用全球性的危险undefined。如果必须与ES3兼容,请替换undefinedvoid 0–请勿求助于typeof。(void一直以来都是一元运算符,其任何操作数的计算结果均为未定义值。)

随着变量如何发挥作用,是时候解决一个实际问题:对象属性。没有理由要使用typeof对象属性。较早的关于特征检测的例外不适用于此处- typeof仅对变量具有特殊的行为,并且引用对象属性的表达式不是变量。

这个:

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

始终完全等同于this³:

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

并考虑到上面的建议,以避免使读者对您为什么使用感到困惑typeof,因为使用它===来检查相等性是最有意义的,因为它可以在以后重构为检查变量的值,并且因为它只是简单的看起来更好,您也应该=== undefined在此始终使用³

关于对象属性,还需要考虑的其他事项是您是否真的要检查undefined。给定的属性名称可以不存在于对象上(undefined在读取时生成值),可以在对象本身上带有值undefined,可以在对象原型上带有值undefined,或者在任何不带值的对象上都可以提供undefined'key' in obj将告诉您密钥是否在对象原型链上的任何位置,并Object.prototype.hasOwnProperty.call(obj, 'key')告诉您密钥是否直接在对象上。不过,在这个答案中,我不会详细介绍原型以及将对象用作字符串键映射的原因,因为它的主要目的是与其他答案中的所有不良建议相抵触,而与对原始问题的可能解释无关。继续阅读MDN上的对象原型更多!

¹示例变量名称的异常选择?这是来自Firefox的NoScript扩展的真正的死代码。
²不过,不要以为总体上不知道范围是可以的。由于滥用动态范围而导致的额外漏洞:零项目1225³
再次假设使用ES5 +环境,并且undefined引用undefined了全局对象的属性。void 0否则替代。


@BenjaminGruenbaum正确,但完全具有误导性。任何非默认上下文都可以定义自己的undefined,隐藏默认上下文。对于大多数实际用途,其作用与覆盖相同。
blgt 2014年

23
@blgt这对任何实际的事情都是偏执和无关紧要的。每个上下文都可以覆盖console.log,重新定义Array原型方法,甚至可以覆盖Function.prototype.call的钩子,以及每次在JavaScript中调用函数时都进行更改。防止这种情况非常偏执并且很愚蠢。就像我(和微型技术公司)所说的那样,您可以void 0用来与未定义的进行比较,但这又是愚蠢的和过度的。
本杰明·格林巴姆2014年

19
我希望我有一个以上的赞成票。这是最正确的答案。我真的想停止typeof something === "undefined") 在代码中看到。
西蒙·鲍姆加特·韦兰德

@BenjaminGruenbaum对于懒惰的程序员,void 0是(一次)都短更安全!那是我书中的胜利。
wizzwizz4'4

4
这确实应该是公认的答案。这是最彻底和最新的。
Patrick Michaelsen

161

在JavaScript中,为null,没有定义。它们具有不同的含义。

  • 未定义表示尚未定义变量值;目前尚不清楚该值是多少。
  • null表示已定义变量值并将其设置为null(无值)。

Marijn Haverbeke在他的免费在线书“ Eloquent JavaScript ”(强调我的)中指出:

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

因此,我猜检查未定义内容的最佳方法是:

if (something == undefined)

希望这可以帮助!

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

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

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

42
if(something == undefined)最好写成好像(something === undefined)
Sebastian Rittau 09年

59
应该指出的是,这并不完全安全。undefined只是可以由用户重新分配的变量:编写undefined = 'a';将导致您的代码不再执行您认为的工作。使用typeof更好,并且还可以用于尚未声明的变量(不仅是属性)。
Gabe Moothart

7
如果某物是未定义的全局变量,(某物==未定义)将引发JavaScript错误。
Morgan Cheng

8
问题在于,如果var a = null,则即使最肯定地定义了a,但== undefined的计算结果仍为true。
安德鲁

6
对“口才的Javascript”注释的这种解释是向后的。如果您确实只想检查未定义的内容,则建议的代码将不起作用(它还将检测已定义的条件,但尚未关联任何值[ienull])。为空值。建议的代码“如果(东西==未定义)......”支票 undefined和null(无设置值),也就是说,它的解释为:“如果((东西是未定义)OR(什么是空))...”什么作者的意思是,你往往是什么真正想要的是检查两个 undefined和null。
Chuck Kollars'5

125

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

实际上,这可能意味着两个截然不同的事情!首先,它可以表示从未在对象中定义的属性,其次,它可以表示具有未定义值属性。让我们看一下这段代码:

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,则引发x.a === undefined此问题。typeof x.a == 'undefined'ReferenceError: x is not defined
  • 变量undefined是全局变量(因此实际上是window.undefined在浏览器中)。因为ECMAScript的第1版已支持,因为ECMAScript的5它是只读的。因此,在现代浏览器中,不能像许多作者喜欢的那样将其重新定义为true,但是对于较旧的浏览器来说,这仍然是正确的。

最终决战:obj.prop === undefinedvstypeof 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支持的全局变量undefinedglobal.undefined(也可以不带'global'前缀使用)。我不知道服务器端JavaScript的其他实现。


@Bergi感谢您的评论。我已经纠正了我的答案。为了辩护,我可以说,目前(从v0.10.18版本开始)Node.js官方文档undefined作为的成员一无所知global。同样,console.log(global);也不for (var key in global) { ... }未定义global的成员。但是测试就像'undefined' in global表明相反。
Konstantin Smolyanin

4
它不需要EmanaScript规范中的额外文档,它也说[[Enumerable]]
不对的

5
关于Minuses of typeof obj.prop == 'undefined'这一点,可以通过写成来避免typeof obj.prop == typeof undefined。这也提供了非常好的对称性。
2014年

3
@hlovdal:与obj.prop === undefined。完全没有意义。
Ry-

1
当我们对问题标题检测未定义的属性”是正确的,而不是第一句(“检查是否未定义...”)中的(不同且容易得多)问题不正确时,您回答if ('foo' in o)……您的回答确实是这里第一个正确答案。几乎其他所有人都回答了这句话。
Frank Nocke

70

问题归结为三种情况:

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

但是如上所述,它们并不完全相同(但足以满足我的需求)。


10
嗨,迈克尔。很好的建议,我认为这确实使事情更清洁。但是,我发现的一个陷阱是使用!时。运算符“ in”。您必须在if (!("x" in blob)) {}中用括号括起来,因为!运算符的优先级高于“输入”。希望能对某人有所帮助。
西蒙东

对不起,迈克尔,但是根据原始问题,这是不正确的,或者至少是误导性的。“输入”不是测试对象属性是否具有typeof undefined的充分方法。为证明起见
tex

2
这两个代码部分做不同的事情!考虑和考虑的对象a = {b: undefined}; 然后typeof a.b === typeof a.c === 'undefined'但是'b' in a!('c' in a)
mgol 2012年

3
+1。OP并未明确说明该属性是否存在并且具有未定义的值,或者该属性本身是否未定义(即不存在)。
RobG

我建议将第一个表中的点(2.)更改为{ x : undefined }或至少添加为表中(2.)的另一种选择-我不得不花一点时间来意识到该点(2.)的计算结果为undefined(尽管您稍后再提到)。
mucaho

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

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


47
括号是不必要的,因为typeof运算是一个操作符
aehlke

12
但是它们使检查的内容更加清楚。否则,它可能会被解读为typeof (something == "undefined")
Abhi Beckert 2012年

:如果您需要括号,那么你应该学会运算符优先级在JS developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
伊恩

11
括号之所以有用是因为您不需要学习JS中的运算符优先级,也不需要推测未来的维护程序员是否需要学习JS中的运算符优先级。
DaveWalley 2014年

27
括号可用于阐明情况。但是在这种情况下,它们只是使运算符看起来像一个函数。毫无疑问,这澄清了程序员的意图。但是,如果不确定运算符的优先级,则应将其写为(typeof something) === "undefined"
罗伯特

42

我不确定用===with 的来源是哪里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

大点的埃里克。检查类型也会对​​性能造成影响吗?
西蒙东

5
@Simon:恰恰相反-在'==='情况下,避免强制会导致性能下降。快速而肮脏的测试表明,在FF5.0.1下,“ ===”比“ ==”快5%
安东尼·哈奇金斯

5
更全面的测试表明,在FF,IE和Chrome下,“ ==”比“ ===”(5-10%)快或少,而Opera根本没有任何区别:jsperf.com/triple- equals-vs-twice-equals / 6
安东尼·哈奇金斯2011年

3
使用==仍然至少需要类型检查-解释器无法在不首先知道它们类型的情况下比较两个操作数。
Alnitak

7
=====:) 少一个字符:
svidgen

25

我从相关问题中交叉回答我的答案如何在JavaScript中检查“未定义”?

特定于此问题,请参阅的测试用例someObject.<whatever>


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

(请注意,在有作用域的包装器中使用varfor 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

21

如果你这样做

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

当变量myvar不存在时,它将失败,因为未定义myvar,因此脚本已损坏,测试无效。

因为窗口对象在函数外部具有全局作用域(默认对象),所以声明将“附加”到窗口对象。

例如:

var myvar = 'test';

全局变量myvarwindow.myvarwindow ['myvar']相同

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

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

变量是否确实存在的问题并不重要,其值不正确。否则,用undefined初始化变量是愚蠢的,最好使用值false进行初始化。当您知道声明的所有变量都用false初始化时,您可以简单地检查其类型或依靠!window.myvar其是否具有正确/有效的值。因此,即使未定义变量!window.myvar,对于myvar = undefinedor myvar = false还是or 都是相同的myvar = 0

当您需要特定类型时,请测试变量的类型。为了加快测试条件,您最好执行以下操作:

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

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

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

(y)


19

我没有看到(希望我没有错过它)有人在属性之前检查对象。因此,这是最短和最有效的(尽管不一定最清晰):

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

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


2
如果您想知道为什么这样做:Javascript:逻辑运算符和true / falsy
mb21

如果您想将属性分配给已定义的变量,则不为null且不为false,否则使用一些默认值,则可以使用: var x = obj && obj.prop || 'default';
Stijn de Witt

我认为问题是要明确检查未定义的内容。您的条件将检查JS的所有错误值。
NikoKyriakid

15

在《探索JavaScript中的Null和Undefined的深渊》一文中,我读到像Underscore.js之类的框架使用此函数:

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

3
void 0只是一种简短的编写方式undefined(因为这是void后跟任何表达式返回的内容),它节省了3个字符。它也可以做var a; return obj === a;,但这又是一个角色。:-)
RobG

2
void是保留字,而undefined不是即同时undefined等于void 0默认情况下,您可以分配一个值,undefinedundefined = 1234
Brian M. Hunt 2015年

isUndefined(obj):16个字符。 obj === void 0:14个字符。没说。
Stijn de Witt

14

只是任何未在JavaScript中定义未定义,是对象/数组中的属性还是简单变量都没有关系...

JavaScript具有typeof使检测未定义变量非常容易的功能。

只需检查是否typeof whatever === 'undefined',它将返回一个布尔值。

这就是isUndefined()AngularJs v.1x中著名的函数的编写方式:

function isUndefined(value) {return typeof value === 'undefined';} 

因此,如您所见,该函数接收到一个值,如果定义了该值,它将返回false,否则,对于未定义的值,将返回true

因此,让我们看一下传递值(包括如下所示的对象属性)时将得到的结果,这是我们拥有的变量的列表:

var stackoverflow = {};
stackoverflow.javascipt = 'javascript';
var today;
var self = this;
var num = 8;
var list = [1, 2, 3, 4, 5];
var y = null;

并且我们按如下方式检查它们,您可以在它们前面看到结果作为注释:

isUndefined(stackoverflow); //false
isUndefined(stackoverflow.javascipt); //false
isUndefined(today); //true
isUndefined(self); //false
isUndefined(num); //false
isUndefined(list); //false
isUndefined(y); //false
isUndefined(stackoverflow.java); //true
isUndefined(stackoverflow.php); //true
isUndefined(stackoverflow && stackoverflow.css); //true

如您所见,我们可以在代码中使用类似这样的内容进行检查,就像您提到的那样,您可以typeof在代码中简单地使用它,但是如果您一遍又一遍地使用它,请创建一个函数,例如我共享的角度样本,并继续重复使用遵循DRY代码模式。

还有一件事,要检查甚至不确定该对象是否存在的实际应用程序中某个对象的属性,请首先检查该对象是否存在。

如果检查对象的属性,但该对象不存在,则会引发错误并停止整个应用程序的运行。

isUndefined(x.css);
VM808:2 Uncaught ReferenceError: x is not defined(…)

如此简单,您可以将if语句包装如下:

if(typeof x !== 'undefined') {
  //do something
}

这也等于在Angular 1.x中定义的...

function isDefined(value) {return typeof value !== 'undefined';}

另外,其他Javascript框架(例如下划线)也具有类似的定义检查,但typeof如果您尚未使用任何框架,建议您使用。

我还从MDN中添加了此部分,该部分提供了有关typeof,undefined和void(0)的有用信息。

严格等于和未定义
您可以使用undefined和严格等于和不相等运算符来确定变量是否具有值。在以下代码中,未定义变量x,并且if语句的值为true。

var x;
if (x === undefined) {
   // these statements execute
}
else {
   // these statements do not execute
}

注意:此处必须使用严格相等运算符而不是标准相等运算符,因为x == undefined还会检查x是否为null,而严格相等则不。null不等于未定义。有关详细信息,请参见比较运算符。


Typeof运算符和undefined
另外,可以使用typeof:

var x;
if (typeof x === 'undefined') {
   // these statements execute
}

使用typeof的原因之一是,如果尚未声明变量,则不会引发错误。

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
   // these statements execute
}

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

}

但是,应避免这种技术。JavaScript是一种静态作用域语言,因此可以通过查看变量是否在封闭的上下文中进行声明来了解是否声明了变量。唯一的例外是全局范围,但是全局范围绑定到全局对象,因此可以通过检查全局对象上属性的存在来检查全局上下文中变量的存在(使用in运算符,例如)。


无效运算符和未定义

void运算符是第三种选择。

var x;
if (x === void 0) {
   // these statements execute
}

// y has not been declared before
if (y === void 0) {
   // throws a ReferenceError (in contrast to `typeof`)
}

更多> 这里


13

' 如果(window.x){} '是错误安全的

您最有可能想要if (window.x)。即使未声明x,此检查也是安全的(var x;), -浏览器不会抛出错误。

示例:我想知道我的浏览器是否支持History API

if (window.history) {
    history.call_some_function();
}

工作原理:

window是一个将所有全局变量作为其成员的对象,尝试访问不存在的成员是合法的。如果尚未声明x或尚未设置x,window.x返回undefined不确定导致错误,如果()对其进行评估。


但是,如果您在Node中运行怎么办?typeof history != 'undefined'实际上在两个系统中都有效。
Stijn de Witt

13

读完这个,我很惊讶我没看到这个。我发现有多种算法可以解决此问题。

从未定义

如果从未定义对象的值,true则将其定义为null或时,这将防止返回undefined。如果您希望为设置为的值返回true,这将很有帮助。undefined

if(obj.prop === void 0) console.log("The value has never been defined");

定义为未定义或从未定义

如果您希望其结果以true的值定义undefined,或者从未定义,则可以简单地使用=== undefined

if(obj.prop === undefined) console.log("The value is defined as undefined, or never defined");

定义为虚假值,未定义,空值或从未定义。

通常,人们要求我提供一种算法来判断值是伪造的undefined还是null。以下作品。

if(obj.prop == false || obj.prop === null || obj.prop === undefined) {
    console.log("The value is falsy, null, or undefined");
}

4
我认为您可以将最后一个示例替换为if (!obj.prop)
Stijn de Witt 2015年

@StijndeWitt,您可以,当我写这篇文章时,我还没有经验,而且我的英语似乎也很糟糕,但是答案中没有任何错误
Travis

3
var obj = {foo: undefined}; obj.foo === void 0-> true。那个“从不定义为undefined”怎么定义?错了
Patrick Roberts

@PatrickRoberts你是对的。当我在2015年2月(在ES6之前)写出此答案时,我概述的第一个选项确实有效,但是现在已经过时了。
特拉维斯


10

与相比void 0,简洁。

if (foo !== void 0)

它不像 if (typeof foo !== 'undefined')


3
但是,如果foo未声明,它将抛出ReferenceError 。
daniel1426 2014年

1
@ daniel1426:因此,如果您的代码中有错误,您想隐藏它而不是修复它?IMO,这不是一个好方法。

这不是用来隐藏错误。这是检测环境属性以定义polyfill的常用方法。例如:if(typeof Promise ==='undefined'){/ * define Promise * /}
gaperton

10

解决方法不正确。在JavaScript中,

null == undefined

将返回true,因为它们都被“转换”为布尔值并且为false。正确的方法是检查

if (something === undefined)

这是身份运算符...


3
要明确的===是类型等于+(原始相等|对象标识),其中原始包含字符串。我认为大多数人'abab'.slice(0,2) === 'abab'.slice(2)如果认为===是身份运算符就认为是不直观的。
clacke

1
错误。如果尚未创建变量,则会引发错误。不应该被投票。改用typeof。
西蒙东

10

您可以使用以下代码获取所有未定义路径的数组。

 function getAllUndefined(object) {

        function convertPath(arr, key) {
            var path = "";
            for (var i = 1; i < arr.length; i++) {

                path += arr[i] + "->";
            }
            path += key;
            return path;
        }


        var stack = [];
        var saveUndefined= [];
        function getUndefiend(obj, key) {

            var t = typeof obj;
            switch (t) {
                case "object":
                    if (t === null) {
                        return false;
                    }
                    break;
                case "string":
                case "number":
                case "boolean":
                case "null":
                    return false;
                default:
                    return true;
            }
            stack.push(key);
            for (k in obj) {
                if (obj.hasOwnProperty(k)) {
                    v = getUndefiend(obj[k], k);
                    if (v) {
                        saveUndefined.push(convertPath(stack, k));
                    }
                }
            }
            stack.pop();

        }

        getUndefiend({
            "": object
        }, "");
        return saveUndefined;
    }

jsFiddle链接


虽然它不会影响代码的有效性,但您有一个错字:getUndefiend应该是getUndefined
icktoofay

8

这是我的情况:

我正在使用REST调用的结果。结果应从JSON解析为JavaScript对象。

我需要捍卫一个错误。如果就用户指定的args错误而言,rest调用的args不正确,则rest调用基本上返回为空。

在使用这篇文章帮助我进行防御时,我尝试了一下。

if( typeof restResult.data[0] === "undefined" ) { throw  "Some error"; }

对于我的情况,如果restResult.data [0] ===“ object”,那么我可以安全地开始检查其余成员。如果未定义,则抛出上述错误。

我的意思是,就我的情况而言,本文中以上所有建议均无效。我并不是说我是对的,每个人都是错误的。我根本不是JavaScript大师,但希望这会对某人有所帮助。


您的typeof警卫实际上并不警惕直接比较无法处理的任何事情。如果restResult未定义或未声明,它将仍然抛出。

在您的情况下,您可以更简单地检查数组是否为空:if(!restResult.data.length) { throw "Some error"; }
Headbank

8

如果定义了新变量,则有一种很好的方法来给新变量分配已定义的属性;如果未定义,则可以为其分配默认值作为后备。

var a = obj.prop || defaultValue;

如果您有一个函数,它会收到一个附加的config属性,则它是合适的:

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

7

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

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

7

通过注释,对于那些想同时检查这两个注释的对象,它是未定义的还是其值为null:

//Just in JavaScript
var s; // Undefined
if (typeof s == "undefined" || s === null){
    alert('either it is undefined or value is null')
}

如果您使用的是jQuery库,那么jQuery.isEmptyObject()这两种情况就足够了,

var s; // Undefined
jQuery.isEmptyObject(s); // Will return true;

s = null; // Defined as null
jQuery.isEmptyObject(s); // Will return true;

//Usage
if (jQuery.isEmptyObject(s)) {
    alert('Either variable:s is undefined or its value is null');
} else {
     alert('variable:s has value ' + s);
}

s = 'something'; // Defined with some value
jQuery.isEmptyObject(s); // Will return false;

jQuery还将解决使用不同JavaScript API的任何跨浏览器兼容性问题。
Henry Heleine

7

如果您使用的是Angular:

angular.isUndefined(obj)
angular.isUndefined(obj.prop)

Underscore.js:

_.isUndefined(obj) 
_.isUndefined(obj.prop) 

2
如何添加1变量x?我需要下划线还是jQuery?(令人惊奇的是,人们甚至会使用库来执行最基本的操作,例如typeof支票)
Stijn de Witt 2015年

6

if (this.variable)用来测试是否已定义。上面推荐的 Simple if (variable),对我来说失败了。事实证明,只有当变量是某个对象的字段时,它才能工作,以检查它是否在字典中定义。但是我们可以使用或作为字典对象,因为据我所知,任何变量都是当前窗口中的一个字段。因此,这是一个测试obj.someFieldthiswindow

if (this.abc) alert("defined"); else alert("undefined");

abc = "abc";
if (this.abc) alert("defined"); else alert("undefined");

它首先检测到变量abc未定义,并且在初始化后定义。


5

对于那些期望得到怪异答案的人,我在这里提供了三种方法:

function isUndefined1(val) {
    try {
        val.a;
    } catch (e) {
        return /undefined/.test(e.message);
    }
    return false;
}
function isUndefined2(val) {
    return !val && val+'' === 'undefined';
}
function isUndefined3(val) {
    const defaultVal={};
    return ((input=defaultVal)=>input===defaultVal)(val);
}
function test(func){
    console.group(`test start :`+func.name);
    console.log(func(undefined));
    console.log(func(null));
    console.log(func(1));
    console.log(func("1"));
    console.log(func(0));
    console.log(func({}));
    console.log(func(function () { }));
    console.groupEnd();
}
test(isUndefined1);
test(isUndefined2);
test(isUndefined3);

isUndefined1:

尝试获取输入值的属性,检查错误消息是否存在。如果输入值未定义,则错误消息将为未捕获TypeError:无法读取未定义的属性'b'

isUndefined2:

将输入值转换为字符串以进行比较,"undefined"并确保它为负值。

isUndefined3:

在js中,当输入值恰好是时,可选参数才有效undefined


4
function isUnset(inp) {
  return (typeof inp === 'undefined')
}

如果设置了变量,则返回false;如果未定义,则返回true。

然后使用:

if (isUnset(var)) {
  // initialize variable here
}

5
不,不要这样做。只需要一个非常简单的测试即可证明您无法将typeof测试有意义地包装在一个函数中。令人惊讶的是,有4个人对此表示赞同。-1。
Stijn de Witt

4

我想向您展示一些我用来保护undefined变量的东西:

Object.defineProperty(window, 'undefined', {});

这禁止任何人更改window.undefined值,因此会破坏基于该变量的代码。如果使用"use strict",任何试图更改其值的操作都会以错误结尾,否则将被忽略。


4

您还可以使用Proxy,它将与嵌套调用一起使用,但需要额外检查一下:

function resolveUnknownProps(obj, resolveKey) {
  const handler = {
    get(target, key) {
      if (
        target[key] !== null &&
        typeof target[key] === 'object'
      ) {
        return resolveUnknownProps(target[key], resolveKey);
      } else if (!target[key]) {
        return resolveUnknownProps({ [resolveKey]: true }, resolveKey);
      }

      return target[key];
    },
  };

  return new Proxy(obj, handler);
}

const user = {}

console.log(resolveUnknownProps(user, 'isUndefined').personalInfo.name.something.else); // { isUndefined: true }

所以您将使用它像:

const { isUndefined } = resolveUnknownProps(user, 'isUndefined').personalInfo.name.something.else;
if (!isUndefined) {
  // do someting
}

4

来自lodash.js。

var undefined;
function isUndefined(value) {
  return value === undefined;
}

它创建一个名为LOCAL的变量undefined,该变量将使用默认值real undefined进行初始化,然后value与该变量进行比较undefined


更新9/9/2019

我发现lodash更新了其实现。请参阅我的问题代码

要防弹,只需使用:

function isUndefined(value) {
  return value === void 0;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.