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

测试JavaScript中变量是否未定义的最合适方法是什么?

我看到了几种可能的方法:

if (window.myVariable)

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

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

你可以使用typeof,像这样:

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

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

您可以检查变量的类型:

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

有时你甚至不必检查类型。如果变量的值在设置时无法评估为false(例如,如果它是一个函数),那么你可以直接评估变量。例子:

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

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

如果你有兴趣找出一个变量是否被声明而不管它的值如何,那么使用in运算符是最安全的方法。考虑这个例子:

// global scopevar theFu; // theFu has been declared, but its value is undefinedtypeof 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 sy值,所以它不是很健壮:

false0""NaNnullundefined

感谢@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 errorObject.defineProperty(window, "myVariable", {get: function() { throw new Error("W00t?"); },set: undefined});if (myVariable) {// Error: W00t?}

我将其用作函数参数并在函数执行时将其排除在外,这样我就得到了“真正的”未定义。尽管它确实需要您将代码放在函数中。我在阅读jQuery源代码时发现了这一点。

undefined = 2;
(function (undefined) {console.log(undefined); // prints out undefined// and for comparison:if (undeclaredvar === undefined) console.log("it works!")})()

当然,您可以只使用typeof。但无论如何,我所有的代码通常都在包含函数中,因此使用此方法可能会在这里和那里节省几个字节。

2020更新

我倾向于typeof检查的原因之一(即undefined可以重新定义)与ECMAScript 5的大规模采用无关。另一个,您可以使用typeof检查未声明变量的类型,始终是利基。因此,我现在建议在大多数情况下使用直接比较:

myVariable === undefined

2010年的原始答案

使用typeof是我的偏好。当变量从未被声明时,它将起作用,不像任何与=====运算符的比较或使用if的类型强制。(undefinednull不同,也可能在ECMAScript 3环境中重新定义,使其不可靠,尽管现在几乎所有常见环境都符合ECMAScript 5或更高版本)。

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

我个人使用

myVar === undefined

警告:请注意,===用于==myVar之前是宣布(而不是定义)。


我不喜欢typeof myVar === "undefined"。我认为它冗长且不必要。(我可以用更少的代码完成相同的工作。)

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

酷。我知道这一点。话说回来,JavaScript中的大多数变量都可以重新定义。你应该永远不要使用任何可以重新定义的内置标识符吗?

如果你遵循这个规则,对你有好处:你不是一个伪君子。

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

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

底线,“它可以被重新定义”参数不使用原始=== undefined是假的。

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


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

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

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

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

考虑:

var iAmUndefined;

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

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

但是等等!还有更多!如果一些原型链魔法正在发生……怎么办?现在即使是高级的in运算符也不够。(好吧,我在这里完成了这部分,除了说99%的时间里,=== undefined(和****咳嗽*****typeof)工作得很好。如果你真的关心,你可以自己阅读这个主题。)

由于其他答案都没有帮助我,我建议这样做。它在Internet Explorer 8中对我有用:

if (typeof variable_name.value === 'undefined') {// variable_name is undefined}

一些场景说明了各种答案的结果: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: truedefinedAndInitialized in window: falsesomeObject.firstProp in window: falsesomeObject.secondProp in window: falsesomeObject.undefinedProp in window: truenotDefined 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: falsetypeof definedButNotInitialized == "undefined": truetypeof definedButNotInitialized === typeof undefined: truedefinedButNotInitialized === undefined: true! definedButNotInitialized: true!! definedButNotInitialized: falsetypeof definedAndInitialized == "undefined": falsetypeof definedAndInitialized === typeof undefined: falsedefinedAndInitialized === undefined: false! definedAndInitialized: false!! definedAndInitialized: truetypeof someObject.firstProp == "undefined": falsetypeof someObject.firstProp === typeof undefined: falsesomeObject.firstProp === undefined: false! someObject.firstProp: false!! someObject.firstProp: truetypeof someObject.secondProp == "undefined": falsetypeof someObject.secondProp === typeof undefined: falsesomeObject.secondProp === undefined: false! someObject.secondProp: true!! someObject.secondProp: falsetypeof someObject.undefinedProp == "undefined": truetypeof someObject.undefinedProp === typeof undefined: truesomeObject.undefinedProp === undefined: true! someObject.undefinedProp: true!! someObject.undefinedProp: falsetypeof notDefined == "undefined": truetypeof notDefined === typeof undefined: truenotDefined === undefined: Exception--ReferenceError: notDefined is not defined! notDefined: Exception--ReferenceError: notDefined is not defined!! notDefined: Exception--ReferenceError: notDefined is not defined

与@Thomas Eding的回答相反:

如果我忘记在代码中声明myVar,那么我将得到myVar is not defined

让我们举一个真实的例子:

我有一个变量名,但我不确定它是否在某处声明。

那么@Anurag的回答会有所帮助:

var myVariableToCheck = 'myVar';if (window[myVariableToCheck] === undefined)console.log("Not declared or declared, but undefined.");
// Or you can check it directlyif (window['myVar'] === undefined)console.log("Not declared or declared, but undefined.");

更新时间2018-07-25

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

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

即使我修改了测试以防止Chrome优化它们,差异也是微不足道的。

chrome://version的相关内容:

  • 谷歌Chrome:67.0.3396.99(官方版本)(64位)(队列:稳定)
  • 修订:a337fbf3c2ab8ebc6b64b0bfdce73a20e2e2252b-refs/分支头/3396@{#790}
  • 操作系统:Windows
  • JavaScript:V8 6.7.288.46
  • User Agent: Mozilla/5.0(Windows NT 10.0; Win64; x64)AppleWebKit/537.36(KHTML,类似Gecko)Chrome /67.0.3396.99Safari /537.36

原创文章2013-11-01

在GoogleChrome中,以下操作比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 msx1  |    1367.8 ns              985.4 ns                988.8 ns

请注意,第一行是秒,而第二行是纳米秒。3.4纳秒的差异不算什么。泰晤士报在随后的测试中非常一致。

这篇文章中,我读到像Underscore.js这样的框架使用这个函数:

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

就个人而言,我总是使用以下内容:

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

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

我更喜欢使用的方法

x === undefined

因为如果x之前没有声明过,它会失败并在我的脸上爆炸,而不是默默地传递/失败。这提醒我x没有声明。我相信JavaScript中使用的所有变量都应该声明。

我知道检查undefined的最可靠方法是使用void 0

这与较新的和较旧的浏览器兼容,并且在某些情况下不能像window.undefined那样被覆盖。

if( myVar === void 0){//yup it's undefined}
    var x;if (x === undefined) {alert ("I am declared, but not defined.")};if (typeof y === "undefined") {alert ("I am not even declared.")};
/* One more thing to understand: typeof ==='undefined' also checksfor if a variable is declared, but no value is assigned. In otherwords, the variable is declared, but not defined. */
// Will repeat above logic of x for typeof === 'undefined'if (x === undefined) {alert ("I am declared, but not defined.")};/* So typeof === 'undefined' works for both, but x === undefinedonly works for a variable which is at least declared. */
/* Say if I try using typeof === undefined (not in quotes) fora variable which is not even declared, we will get run atime error. */
if (z === undefined) {alert ("I am neither declared nor defined.")};// I got this error for z ReferenceError: z is not defined
// x has not been defined beforeif (typeof x === 'undefined') { // Evaluates to true without errors.// These statements execute.}
if (x === undefined) { // Throws a ReferenceError
}