在JavaScript中,测试变量是否未定义的最合适方法是什么?
我看到了几种可能的方式:
if (window.myVariable)
或者if (typeof(myVariable) != "undefined")
或。if (myVariable) // This throws an error if undefined. Should this be in Try/Catch?
在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
运算符,它保证返回一个字符串:
如果你想知道变量是否未定义或是否具有值undefined
,那么请使用typeof
运算符,它保证返回一个字符串:
if (typeof myVar !== 'undefined')
与undefined
进行直接比较是有问题的,因为undefined
可能被覆盖。
window.undefined = "foo";
"foo" == undefined // true
正如@CMS所指出的,这个问题已在ECMAScript第5版中修复,undefined
是不可写的。
if (window.myVar)
也会包括这些falsy值,所以它不太健壮:
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?
}
myVariable
没有被声明,第三种情况会抛出一个ReferenceError
。 - Christian C. Salvadóundefined
现在被描述为不可写、不可配置和不可枚举的。因此,在严格模式下,window.undefined = "omg";
将会静默失败或抛出错误。 - Christian C. Salvadóundefined
是不可变的。设置 window.undefined
不会产生任何效果。 - Paul S.我个人使用
myVar === undefined
警告:请注意使用===
而不是==
,并且myVar
已经被先前声明(而非定义)。
我不喜欢typeof myVar === "undefined"
。我认为它太啰嗦,没有必要。(我可以用更少的代码实现同样的功能。)
现在有些人会阅读这篇文章感到痛苦并尖叫:“等等!等等!!!undefined
可以被重新定义!”
没错,我知道这一点。但是,Javascript 中的大多数变量都可以被重新定义。难道你永远不应该使用任何可以被重新定义的内置标识符吗?
如果你遵循这个规则,那就很好,你不是伪君子。
问题是,在JS中做许多真正的工作时,开发人员需要依赖于可重新定义的标识符。我没有听到有人告诉我不应该使用setTimeout
,因为某个人可以......
window.setTimeout = function () {
alert("Got you now!");
};
总之,使用“可以重新定义”的论点来避免使用原始的 === undefined
是不可信的。
(如果您仍然担心 undefined
被重新定义,那么为什么要盲目地将未经测试的库代码集成到您的代码库中呢?或者更简单:使用一个linting工具。)
此外,像 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
)就可以正常工作。如果你真的在意,你可以自己阅读关于这个主题的文章。)
undefined
,因此重新定义undefined
的可能性略微增加。有些人习惯性地将常量放在左侧进行此类检查:if (undefined == someVariable)
。只需要一个打字错误就会悄悄地重新定义undefined
:if (undefined = someVariable)
。 - Tim Downundefined
赋值给左手边变量的代码。即便我犯了这个错误,我使用 ===
而非 ==
也能大大降低出错概率。但是,使用 ==
的确是一个更加令人担忧的问题。无论如何,像这样的 Bug 通常很容易被发现。就像这个 Bug:typeof x == "undefned"
。 - Thomas EdingmyVar
确实未定义,代码将会抛出错误,而且很容易进行测试 - http://jsfiddle.net/WcM5g/ 正确的方式是 typeof myVar === 'undefined'
。 - laurentvar
关键字或函数参数。在任何情况下,我都不会有意编写尝试操作未声明变量的代码。请记住,在 JS 中,未声明和未定义是两个不同的概念。 - Thomas Edingif(NULL = myVar)
无法编译并立即被捕获,而if(myVar = NULL)
会创建一个可能难以跟踪的错误,具体取决于周围的其他代码。现代编译器应该会给出警告,但许多经验丰富的C程序员已经养成了交换顺序的习惯。 - GrandOpener2020更新
我之前更喜欢使用 typeof
进行检查的原因之一(即 undefined
可以被重新定义),随着 ECMAScript 5 的普及已经不再具有意义。另一个原因是你可以使用 typeof
来检查未声明变量的类型,但这个情况一直比较少见。因此,我现在建议在大多数情况下使用直接比较:
myVariable === undefined
2010年的原始回答
我更喜欢使用typeof
。它可以在变量从未被声明时起作用,而与==
或===
运算符的任何比较或使用if
进行类型强制转换不同(undefined
与null
不同,在 ECMAScript 3 环境中可能也被重新定义,因此不能保证其可靠性,但几乎所有常见环境现在都符合ECMAScript 5或以上)。
if (typeof someUndeclaredVariable == "undefined") {
// Works
}
if (someUndeclaredVariable === undefined) {
// Throws an error
}
'xyz' in window
比typeof xyz == "undefined"
更好,因为它检查的是错误的内容。in
运算符检查属性是否存在,而不管其值如何,而问题至少似乎在询问如何测试变量的值是否为“undefined”。也许我选择的一个更好的例子应该是var foo; "foo" in window
;这会返回true,而foo
肯定是未定义的。 - Tim Downxyz === undefined
比 typeof xyz == "undefined"
更好?我同意关于全局变量的问题,但我们两个人中只有你一直在推荐检查 window
的属性。 - Tim Downtypeof
,像这样:if (typeof something != "undefined") {
// ...
}
something !== undefined
来判断。 - Jamestypeof
。 - Thomas Edingtypeof
是最安全和最不容易出错的选项。与其写这样令人困惑的评论,我倒不如编辑答案,换用另一个术语代替“需要”。例如像“你可以|应该|最好|可能使用 typeof
”这样的说法 :) - Kamafeather自从发布这篇文章已近五年,JavaScript 已经迈进了很长的一步。在重复原始文章中的测试时,我发现以下测试方法之间没有一致的差异:
abc === undefined
abc === void 0
typeof abc == 'undefined'
typeof abc === 'undefined'
即使我修改测试以防止 Chrome 将其优化掉,差异也微不足道。因此,我现在建议使用 abc === undefined
来提高清晰度。
来自 chrome://version
的相关内容:
在 Google Chrome 中,以下方法比使用 typeof
测试略微快一些:
if (abc === void 0) {
// Undefined
}
差异可以忽略不计。但是,对于了解 void 0
含义的人来说,这段代码更加简洁、一目了然。请注意,abc
仍然需要被声明。
typeof
和 void
都比直接与 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纳秒的差异微不足道。在后续测试中,时间相当稳定。void 0
对我来说听起来更不寻常;2)你应该分享你的性能测试,但主要是3)如果abc
未定义,则你的第一个示例(abc === void 0
)会抛出异常。 - drzaustypeof
测试。 - Zenexer如果它是未定义的,那么它不会等于包含字符"undefined"的字符串,因为该字符串并不是未定义的。
您可以检查变量的类型:
if (typeof(something) != "undefined") ...
有时候你甚至不需要检查类型。如果变量的值被设置为不能评估为false(例如是一个函数),那么你可以直接评估这个变量。示例:
有时候你甚至不需要检查类型。如果变量的值被设置为不能评估为false(例如是一个函数),那么你可以直接评估这个变量。示例:
if (something) {
something(param);
}
typeof
是一个操作符,而非函数。 - Tim Downif (typeof foo == 'undefined') {
// Do something
};
请注意,这种情况下不必使用严格比较运算符(!==
),因为 typeof
总是返回一个字符串。
};
) 有什么作用? - Jamesif
块可以被视为一行代码进行重写,然后附加分号就有意义了,因为这是我几乎每个其他语句的结束方式。if (typeof foo == 'undefined') { };
此外,这还确保与某些JavaScript缩小器兼容。我知道JSLint不建议这样做,但我只是看不出来有什么意义 - 这些分号是无害的,如果有什么区别,它们会强制执行稍微严格一点的编码风格。 - Mathias Bynensif(){}
而需要加;
的缩小器...你指的是哪些缩小器呢?你说这是你结束每个其他语句的方式...我想这是正确的。但是,代码块{}
本身就是一个语句。加上;
会使其成为两个语句,从语法上讲,这是多余的。即使是自动分号插入也不会在那里加上分号... - Jamesfunction() {}
声明后期望有分号。不过你是对的——显然在if
语句后面不需要分号,但不知怎么的我仍觉得加上分号有意义。 - Mathias Bynens以下是各种答案结果的一些场景示例: 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
undefined
;这不仅可以防止(不寻常的)情况“哦,但是undefined
可以被重新定义”,而且还有助于缩小文件大小。 - drzaus就我个人而言,我总是使用以下内容:
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中使用的所有变量都应该被声明。
undefined
:(function($, undefined){ /* undefined在这里是'abc' */ })(jQuery, 'abc');
,这也是人们抱怨它在技术上不安全的原因,除非您百分之百确定自己的代码在何处运行。 - drzaus
undefined
,还是包括null
? - Nick Craver