jQuery Core Style Guidelines 建议了两种不同的方法来检查变量是否已定义。
全局变量:typeof 变量 === "undefined"
局部变量:变量 === 未定义
属性:object.prop === 未定义
为什么 jQuery 对全局变量使用一种方法,而对局部变量和属性使用另一种方法?
foo === undefined
正在检查 undefined 的本地副本而不是全局 (window.undefined),后者可能已被疯狂的代码修改。 undefined 是可变的这一事实绝对值得注意,我很高兴你做到了。 (+1)
对于未声明的变量,typeof foo
将返回字符串文字 "undefined"
,而身份检查 foo === undefined
将触发错误 “foo is not defined”。
对于局部变量(您知道在某处声明),不会发生此类错误,因此需要进行身份检查。
我会坚持在任何地方使用 typeof foo === "undefined"
。那永远不会出错。
我想 jQuery 推荐这两种不同方法的原因是它们在 jQuery 代码所在的函数中定义了自己的 undefined
变量,因此在该函数中 undefined
是安全的,不会被外部篡改。我还可以想象某个地方的某个人对这两种不同的方法进行了基准测试,发现 foo === undefined
更快,因此决定这是要走的路。 [更新:如评论中所述,与 undefined
的比较也略短,这可能是一个考虑因素。] 但是,在实际情况下的收益将完全微不足道:此检查永远不会,永远是任何类型的瓶颈,并且您失去的东西很重要:评估主机对象的属性以进行比较可能会引发错误,而 typeof
检查永远不会。
例如,在 IE 中使用以下代码来解析 XML:
var x = new ActiveXObject("Microsoft.XMLDOM");
要安全地检查它是否具有 loadXML
方法:
typeof x.loadXML === "undefined"; // Returns false
另一方面:
x.loadXML === undefined; // Throws an error
更新
我忘记提及的 typeof
检查的另一个优点是它也适用于未声明的变量,而 foo === undefined
检查不这样做,实际上会抛出 ReferenceError
。感谢@LinusKleen 提醒我。例如:
typeof someUndeclaredVariable; // "undefined"
someUndeclaredVariable === undefined; // throws a ReferenceError
底线:始终使用 typeof
检查。
foo === undefined
最小化后可能类似于 f===u
,而 typeof foo === "undefined"
只能减少为 typeof f==="undefined"
。
var u = "undefined"
并将其缩减为 typeof f==u
,这会改进但仍然更大。
typeof
对未声明变量的安全性是否是一个优势。如果有什么让错别字更容易漏掉的话,我看不出你什么时候真正想要检查未声明变量的类型。
使用 typeof-variant 的另一个原因:undefined
可以重新定义。
undefined = "foo";
var variable = "foo";
if (variable === undefined)
console.log("eh, what?!");
typeof variable
的结果不能。
更新:请注意,在 ES5 中并非如此,全局 undefined
是不可配置、不可写的属性:
15.1.1 全局对象的值属性 [...] 15.1.1.3 undefined undefined 的值是 undefined(见 8.1)。该属性具有属性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }。
但它仍然可以被局部变量遮蔽:
(function() {
var undefined = "foo";
var variable = "foo";
if (variable === undefined)
console.log("eh, what?!");
})()
或参数:
(function(undefined) {
var variable = "foo";
if (variable === undefined)
console.log("eh, what?!");
})("foo")
undefined
属性不能在 ES5 中重新定义,但仍然可以使用局部变量进行遮蔽。 void 0
更短更安全。
因为 undefined
并不总是被声明,而是 jQuery 在其主函数中声明了 undefined
。所以他们在内部使用安全的 undefined
值,但在外部,他们使用 typeof
样式是安全的。
对variable === undefined
的性能提升有兴趣的可以看看这里,不过好像只是chrome优化。
http://jsperf.com/type-of-undefined-vs-undefined/30
http://jsperf.com/type-of-undefined-vs-undefined
对于局部变量,使用 localVar === undefined
检查会起作用,因为它们必须是在局部范围内的某个地方定义的,否则它们不会被视为局部变量。
对于不是本地且未在任何地方定义的变量,检查 someVar === undefined
将抛出异常:Uncaught ReferenceError: j is not defined
这是一些代码,可以澄清我上面所说的内容。请注意内联注释以获得进一步的清晰度。
function f (x) {
if (x === undefined) console.log('x is undefined [x === undefined].');
else console.log('x is not undefined [x === undefined.]');
if (typeof(x) === 'undefined') console.log('x is undefined [typeof(x) === \'undefined\'].');
else console.log('x is not undefined [typeof(x) === \'undefined\'].');
// This will throw exception because what the hell is j? It is nowhere to be found.
try
{
if (j === undefined) console.log('j is undefined [j === undefined].');
else console.log('j is not undefined [j === undefined].');
}
catch(e){console.log('Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.');}
// However this will not throw exception
if (typeof j === 'undefined') console.log('j is undefined (typeof(x) === \'undefined\'). We can use this check even though j is nowhere to be found in our source code and it will not throw.');
else console.log('j is not undefined [typeof(x) === \'undefined\'].');
};
如果我们这样调用上面的代码:
f();
输出将是这样的:
x is undefined [x === undefined].
x is undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.
如果我们像这样调用上面的代码(实际上是任何值):
f(null);
f(1);
输出将是:
x is not undefined [x === undefined].
x is not undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.
当您进行这样的检查时:typeof x === 'undefined'
,您实际上是在问:请检查变量 x
是否存在(已定义)在源代码中的某处。(或多或少) .如果您了解 C# 或 Java,则永远不会进行此类检查,因为如果不存在,则无法编译。
概括:
在全局范围内,如果变量未声明或值为 undefined
,我们实际上希望返回 true:
变量 globalVar1; // 此变量已声明,但未定义,因此值为 undefined console.log(globalVar1 === undefined); // 这个变量没有声明,因此会抛出一个referenceError console.log(globalVar2 === undefined);
因为在全局范围内,我们不能 100% 确定是否声明了一个变量,这可能会给我们一个 referenceError。当我们在未知变量上使用 typeof
运算符时,如果未声明变量,我们不会遇到此问题:
变量 globalVar1; console.log(typeof globalVar1 === 'undefined'); console.log(typeof globalVar2 === 'undefined');
这是因为 typeof
运算符在未声明变量或当前持有值 undefined
时返回字符串 undefined
,这正是我们想要的。
使用局部变量我们没有这个问题,因为我们事先知道这个变量会存在。如果变量存在,我们可以简单地查看相应的函数。
对于对象属性,我们没有这个问题,因为当我们尝试查找不存在的对象属性时,我们也会得到值 undefined
变量 obj = {}; console.log(obj.myProp === undefined);
在节点 v6.9.1 上,typeof a === 'undefined'
比 a === 'undefined'
快约 2 倍。
undefined
,而不是 'undefined'
typeof foo; // -> "undefined"
) 以强调它是一个字符串而不是原始值undefined
。