变量===未定义vs. typeof变量===“未定义”


300

jQuery的核心风格指南建议两种不同的方法来检查一个变量是否被定义。

  • 全局变量: typeof variable === "undefined"
  • 局部变量: variable === undefined
  • 特性: object.prop === undefined

为什么jQuery为什么对全局变量使用一种方法而对局部变量和属性使用另一种方法?


关于JQuery为什么要同时使用这两种方法,我无法回答,但是Javascript确实有一些有趣的怪癖,这意味着这两件事有细微的不同。大部分时间都没关系(例如,您的代码是否合理),但是仍然存在差异:请参见此处的写作-wtfjs.com/2010/02/15/undefined-is-mutable
Spudley

2
正如@Struppi指出的那样,jQuery的最外层函数具有一个名为undefined的参数。在jQuery中,foo === undefined检查的是undefined的本地副本,而不是全局的(window.undefined),后者可能已由疯狂的代码修改。undefined易变的事实绝对值得一提,我很高兴您做到了。(+1)
Patrick McElhaney 2011年

Answers:


366

对于未声明的变量,typeof foo将返回字符串文字"undefined",而身份检查foo === undefined将触发错误“未定义foo”

对于局部变量(您知道已在某处声明),不会发生此类错误,因此进行身份检查。


3
@goreSplatter您现在不能删除它。:-)很难选择,但是用措辞表达方式,此答案更合适。任何对undefined的工作方式感兴趣的人(像我一样)也应该查看其他答案,尤其是@Tim的答案。
Patrick McElhaney 2011年

4
我要加引号(typeof foo; // -> "undefined")以强调它是一个字符串,而不是原始值undefined
13年

117

我会坚持typeof foo === "undefined"到处使用。那永远不会出错。

我可以想象jQuery之所以推荐这两种不同的方法,是因为它们undefined在jQuery代码所驻留的函数中定义了自己的变量,因此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支票。


10
谢谢蒂姆。您关于性能的观点是有道理的。jQuery团队可能更担心文件大小的影响。foo === undefined最小化时,可能类似于f===u,而typeof foo === "undefined"只能减少为typeof f==="undefined"
Patrick McElhaney 2011年

1
您可以定义var u = "undefined"它并将其减少为typeof f==u,虽然可以改善但仍然更大。
蒂姆·唐

5
好点了,但是我不确定typeof反对未声明变量的安全性是否是优势。如果有的话,它会使错别字更容易溜走,而且我看不到您何时真正要检查未声明变量的类型。
大卫·唐

2
@ Box9:我可以想象在一个库中使用它来检查是否存在另一个库。
Tim Down'1

2
@jontro:那是不使用JSLint的原因之一。
Tim Down

29

使用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是未定义的(见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")

17
无法在ES5中重新定义。
Ry-

6
全局undefined属性无法在ES5中重新定义,但仍可以被局部变量遮盖。void 0更短更安全。
Oriol

7

因为 undefined并非总是声明,但是jQuery undefined在其主要函数中声明。因此,他们在undefined内部使用安全值,但在外部,则使用typeof样式来确保安全。



1

对于局部变量,使用with localVar === undefined可以进行检查,因为它们必须已在局部范围内的某个位置定义,否则将不被视为局部变量。

对于不在局部且未在任何地方定义的变量,检查someVar === undefined将引发异常:Uncaught ReferenceError:j未定义

这是一些代码,这些代码将阐明我在上面所说的内容。请注意内联注释,以进一步明确

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,则永远不会进行这种检查,因为如果不存在,则将无法编译。

<==摆弄我==>


1

摘要:

在全局范围内,如果变量未声明或具有值,我们实际上想返回true undefined

var globalVar1;

// This variable is declared, but not defined and thus has the value undefined
console.log(globalVar1 === undefined);

// This variable is not declared and thus will throw a referenceError
console.log(globalVar2 === undefined);

因为在全局范围内,我们不能100%确定是否声明了变量,否则可能会给我们带来referenceError。当我们typeof在未知变量上使用运算符时,未声明变量时不会出现此问题:

var globalVar1;

console.log(typeof globalVar1 === 'undefined');
console.log(typeof globalVar2 === 'undefined');

这是由于以下事实:当未声明变量或当前持有的正是我们想要的值时,typeof运算符将返回字符串。undefinedundefined


  • 使用局部变量,我们不会遇到这个问题,因为我们事先知道该变量将存在。如果存在变量,我们可以简单地查看相应的函数。
  • 使用对象属性时,我们不会遇到这个问题,因为当我们尝试查找不存在的对象属性时,我们也会获得该值 undefined

var obj = {};

console.log(obj.myProp === undefined);


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.