如何在 JavaScript 中检查 “未定义”?

测试 JavaScript 中是否未定义变量的最合适方法是什么?我已经看到了几种可能的方法:

if (window.myVariable)

要么

if (typeof(myVariable) != "undefined")

要么

if (myVariable) //This throws an error if undefined. Should this be in Try/Catch?

答案

如果您有兴趣了解变量的值是否已声明,那么使用in运算符是最安全的方法。考虑以下示例:

// global scope
var theFu; // theFu has been declared, but its value is undefined
typeof theFu; // "undefined"

但这在某些情况下可能不是预期的结果,因为已声明但未初始化变量或属性。使用in运算符可以进行更强大的检查。

"theFu" in window; // true
"theFoo" in window; // false

如果您想知道变量是否尚未声明或值是否为undefined ,请使用typeof运算符,该运算符可确保返回字符串:

if (typeof myVar !== 'undefined')

直接比较undefined非常麻烦,因为undefined可能会被覆盖。

window.undefined = "foo";
"foo" == undefined // true

正如 @CMS 指出的那样,此问题已在 ECMAScript 第 5 版中进行了修补,并且undefined是不可写的。

if (window.myVar)还将包含这些伪造的值,因此它不是很可靠:

false
0
""
NaN
null
undefined

感谢 @CMS 指出您的第三种情况if (myVariable)在两种情况下也会引发错误。第一个是未定义变量时抛出ReferenceError

// abc was never declared.
if (abc) {
    // ReferenceError: abc is not defined
}

另一种情况是已定义变量,但具有 getter 函数,该函数在调用时会引发错误。例如,

// or it's a property that can throw an error
Object.defineProperty(window, "myVariable", { 
    get: function() { throw new Error("W00t?"); }, 
    set: undefined 
});
if (myVariable) {
    // Error: W00t?
}

我个人使用

myVar === undefined

警告:请注意, ===用于==之上,并且myVar先前已声明未定义 )。


我不喜欢typeof myVar === "undefined" 。我认为这是漫长而不必要的。 (我可以用更少的代码来完成相同的工作。)

现在,有些人在读这篇文章时会痛苦地大喊:“等等!WAAITTT !!! undefined可以重新定义!”

凉。我知道这个。再一次,可以重新定义 Javascript 中的大多数变量。您是否永远不要使用任何可以重新定义的内置标识符?

如果遵守此规则,对您有好处:您不是伪君子。

问题是,为了在 JS 中完成大量实际工作,开发人员需要依靠可重新定义的标识符来实现它们。我没有听到有人告诉我我不应该使用setTimeout因为有人可以

window.setTimeout = function () {
    alert("Got you now!");
};

最重要的是,“可以重新定义” 参数不使用原始=== undefined是伪造的。

(如果仍然害怕重新定义undefined ,为什么要盲目地将未经测试的库代码集成到代码库中?或更简单的是:一种整理工具。)


另外,像typeof方法一样,此技术可以 “检测” 未声明的变量:

if (window.someVar === undefined) {
    doSomething();
}

但是,这两种技术都在其抽象中泄漏。我敦促你不要使用这个甚至

if (typeof myVar !== "undefined") {
    doSomething();
}

考虑:

var iAmUndefined;

要了解是否声明了该变量,您可能需要求助于in运算符。 (在许多情况下,您可以简单地读取代码 O_o)。

if ("myVar" in window) {
    doSomething();
}

可是等等!还有更多!如果某种原型链魔术正在发生…… 该怎么办?现在,即使是上级in运营商是不够的。 (好吧,我在这里完成了这一部分,只是说在 99%的时间里, === undefined (和 **** cough **** typeof )都很好。如果您真的很在意,可以单独阅读此主题。)

我喜欢使用typeof 。当从未声明过变量时,它将起作用,这与与=====运算符进行任何比较,或使用if强制输入类型进行比较。 ( undefined不同于null ,它也可以在 ECMAScript 3 环境中重新定义,因此比较起来不可靠,尽管现在几乎所有常见环境都符合 ECMAScript 5 或更高版本。)

if (typeof someUndeclaredVariable == "undefined") {
    // Works
}

if (someUndeclaredVariable === undefined) { 
    // Throws an error
}

您需要使用typeof

if (typeof something != "undefined") {
    // ...
}

更新 2018-07-25

自从这篇文章首次发表以来已经过去了近五年,JavaScript 已经走了很长一段路。在重复原始帖子中的测试时,我发现以下测试方法之间没有一致的区别:

  • abc === undefined
  • abc === void 0
  • typeof abc == 'undefined'
  • typeof abc === 'undefined'

即使我修改了测试以防止 Chrome 对其进行优化,两者之间的差异也微不足道。因此,为清晰起见,我现在建议abc === undefined

chrome://version相关内容:

  • Google Chrome:67.0.3396.99(正式版本)(64 位)(同类:稳定)
  • 修订:a337fbf3c2ab8ebc6b64b0bfdce73a20e2e2252b-refs / branch-heads / 3396 @ {#790}
  • 操作系统:Windows
  • JavaScript:V8 6.7.288.46
  • 用户代理:Mozilla / 5.0(Windows NT 10.0; Win64; x64)AppleWebKit / 537.36(KHTML,如 Gecko)Chrome / 67.0.3396.99 Safari / 537.36

原帖 2013-11-01

在 Google Chrome 浏览器中,以下内容比typeof测试要快得多:

if (abc === void 0) {
    // Undefined
}

差异可忽略不计。但是,此代码更简洁,对于知道void 0意味着什么的人来说一目了然。但是请注意, 仍然必须声明 abc

typeofvoid都比直接与undefined相比要快得多。我在 Chrome 开发者控制台中使用了以下测试格式:

var abc;
start = +new Date();
for (var i = 0; i < 10000000; i++) {
    if (TEST) {
        void 1;
    }
}
end = +new Date();
end - start;

结果如下:

Test: | abc === undefined      abc === void 0      typeof abc == 'undefined'
------+---------------------------------------------------------------------
x10M  |     13678 ms               9854 ms                 9888 ms
  x1  |    1367.8 ns              985.4 ns                988.8 ns

请注意,第一行以毫秒为单位,而第二行以纳秒为单位。相差 3.4 纳秒没什么。在随后的测试中,时间是相当一致的。

如果未定义,则它将不等于包含字符 “undefined” 的字符串,因为该字符串不是未定义的。

您可以检查变量的类型:

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

有时,您甚至不必检查类型。如果设置后变量的值不能为假(例如,如果它是一个函数),则可以对变量求值。例:

if (something) {
  something(param);
}
if (typeof foo == 'undefined') {
 // Do something
};

请注意,在这种情况下,不必进行严格比较( !== ),因为typeof将始终返回字符串。

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

(请注意,在范围内的包装器中, in测试中使用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

这篇文章中我读到这样的框架Underscore.js使用此功能:

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

就个人而言,我始终使用以下内容:

var x;
if( x === undefined) {
    //Do something here
}
else {
   //Do something else here
}

在所有现代浏览器(JavaScript 1.8.5 或更高版本)中,window.undefined 属性均不可写。从 Mozilla 的文档中: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined ,我看到了:使用 typeof()的一个原因是,如果出现以下情况,它不会引发错误:该变量尚未定义。

我更喜欢有使用的方法

x === undefined

因为它失败了并且炸毁了我的脸,而不是在以前没有声明过 x 的情况下默默地通过 / 失败。这提醒我未声明 x。我相信应该声明 JavaScript 中使用的所有变量。