变量===未定义与类型变量===“未定义”

发布于 2024-10-12 11:10:32 字数 349 浏览 10 评论 0原文

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

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

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

The jQuery Core Style Guidelines suggest two different ways to check whether a variable is defined.

  • Global Variables: typeof variable === "undefined"
  • Local Variables: variable === undefined
  • Properties: object.prop === undefined

Why does jQuery use one approach for global variables and another for locals and properties?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

清音悠歌 2024-10-19 11:10:32

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

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

For undeclared variables, typeof foo will return the string "undefined", whereas the identity check foo === undefined would trigger the error "foo is not defined".

For local variables (which you know are declared somewhere), no such error would occur, hence the identity check.

℡Ms空城旧梦 2024-10-19 11:10:32

我会坚持在任何地方使用 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

UPDATE

的另一个优点我忘记提及的 typeof 检查是它也适用于未声明的变量,而 foo === undefined 检查则不然,实际上会抛出一个 ReferenceError。感谢@LinusKleen 提醒我。例如:

typeof someUndeclaredVariable; // "undefined"
someUndeclaredVariable === undefined; // throws a ReferenceError

底线:始终使用 typeof 检查。

I'd stick to using typeof foo === "undefined" everywhere. That can never go wrong.

I imagine the reason why jQuery recommends the two different methods is that they define their own undefined variable within the function that jQuery code lives in, so within that function undefined is safe from tampering from outside. I would also imagine that someone somewhere has benchmarked the two different approaches and discovered that foo === undefined is faster and therefore decided it's the way to go. [UPDATE: as noted in the comments, the comparison with undefined is also slightly shorter, which could be a consideration.] However, the gain in practical situations will be utterly insignificant: this check will never, ever be any kind of bottleneck, and what you lose is significant: evaluating a property of a host object for comparison can throw an error whereas a typeof check never will.

For example, the following is used in IE for parsing XML:

var x = new ActiveXObject("Microsoft.XMLDOM");

To check whether it has a loadXML method safely:

typeof x.loadXML === "undefined"; // Returns false

On the other hand:

x.loadXML === undefined; // Throws an error

UPDATE

Another advantage of the typeof check that I forgot to mention was that it also works with undeclared variables, which the foo === undefined check does not, and in fact throws a ReferenceError. Thanks to @LinusKleen for reminding me. For example:

typeof someUndeclaredVariable; // "undefined"
someUndeclaredVariable === undefined; // throws a ReferenceError

Bottom line: always use the typeof check.

孤独患者 2024-10-19 11:10:32

使用 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")

Yet another reason for using the typeof-variant: undefined can be redefined.

undefined = "foo";
var variable = "foo";
if (variable === undefined)
  console.log("eh, what?!");

The result of typeof variable cannot.

Update: note that this is not the case in ES5 there the global undefined is a non-configurable, non-writable property:

15.1.1 Value Properties of the Global Object
[...]
15.1.1.3 undefined
The value of undefined is undefined (see 8.1). This property has the attributes
{ [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

But it still can be shadowed by a local variable:

(function() {
  var undefined = "foo";
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})()

or parameter:

(function(undefined) {
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})("foo")
清旖 2024-10-19 11:10:32

variable === undefined 的性能提升感兴趣的人可以看一下这里,但这似乎只是 chrome 优化。

Who is interested in the performance gain of variable === undefined, may take a look here, but it seems to be a chrome optimization only.

ゃ人海孤独症 2024-10-19 11:10:32

因为 undefined 并不总是被声明,但是 jQuery 在它的 main 函数中声明了 undefined 。因此,他们在内部使用安全的 undefined 值,但在外部,他们使用 typeof 样式来保证安全。

Because undefined is not always declared, but jQuery declares undefined in its main function. So they use the safe undefined value internally, but outside, they use the typeof style to be safe.

我纯我任性 2024-10-19 11:10:32

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

对于非本地且未在任何地方定义的变量,检查 someVar === undefined 将抛出异常:Uncaught ReferenceError: j is not Define

这里有一些代码可以澄清我上面所说的。 请注意内嵌注释以进一步清晰

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,则永远不会执行此类检查,因为如果它不存在,则不会编译。

<== 摆弄我==>

For local variables, checking with localVar === undefined will work because they must have been defined somewhere within the local scope or they will not be considered local.

For variables which are not local and not defined anywhere, the check someVar === undefined will throw exception: Uncaught ReferenceError: j is not defined

Here is some code which will clarify what I am saying above. Please pay attention to inline comments for further clarity.

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\'].');
};

If we call the above code like this:

f();

The output would be this:

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.

If we call the above code like these (with any value actually):

f(null); 
f(1);

The output will be:

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.

When you do the check like this: typeof x === 'undefined', you are essentially asking this: Please check if the variable x exists (has been defined) somewhere in the source code. (more or less). If you know C# or Java, this type of check is never done because if it does not exist, it will not compile.

<== Fiddle Me ==>

烙印 2024-10-19 11:10:32

摘要:

在全局范围内,如果变量未声明或值为 undefined,我们实际上希望返回 true:

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% 确定是否声明了变量,这可能会给我们带来引用错误。当我们对未知变量使用 typeof 运算符时,如果未声明该变量,我们不会遇到此问题:

var globalVar1;

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

这是因为,当变量未声明或当前持有值 undefined 时,typeof 运算符返回字符串 undefined,该值恰好是我们想要什么。


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

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

Summary:

When at global scope we actually want to return true if the variable is not declared or has the value 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);

Because in global scope we are not 100% sure if a variable is declared this might give us a referenceError. When we use the typeof operator on the unknown variable we are not getting this issue when the variable is not declared:

var globalVar1;

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

This is due to the fact that the typeof operator returns the string undefined when a variable is not declared or currently hold the value undefined which is exactly what we want.


  • With local variables we don't have this problem because we know beforehand that this variable will exist. We can simply look in the respective function if the variable is present.
  • With object properties we don't have this problem because when we try to lookup an object property which does not exist we also get the value undefined

var obj = {};

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

匿名。 2024-10-19 11:10:32

jQuery 可能希望您在以后的函数中使用 letconst 变量,而在 JavaScript 的 ES6 2015 设计中不允许您这样做使用任何本地作用域(函数)letconst 变量,直到它们被声明。即使通过 Javascript 提升也不允许您对它们进行类型检查!

如果您尝试这样做,JavaScript 会生成一个错误,这与 var 变量不同,后者在提升时会创建一个已声明但未初始化的变量,您可以键入 check 或 check 来查看其是否未定义。

如果您在函数中声明了 letconst 变量,但在尝试访问它之后,typeof 检查仍然会在 JavaScript 中产生引用错误!它的行为非常奇怪,对我来说,为什么要这样设计是不合逻辑的。但这就是为什么 jQuery 可能认为 typeof 函数变量的使用没有用处。示例:

function MyError(){ 

    // WOW! This variable DOES NOT EVEN EXIST, but you can still check its type!
    if(typeof x === 'undefined')
    {
        alert(1);// OK!
    }

    // ERROR!
    // WOW! You cannot even check an existing "let" variable's TYPE in a local function!
    if(typeof y === 'undefined')//REFERENCE ERROR!!
    {
        alert(2);
    }
    // We defined the variable so its hoisted to the top but in a dead zone
    let y = 'test';
}

MyError();

// RESULT
// alert 1 fires but a REFERENCE ERROR is generated from the second alert 2 condition.

上面的奇怪之处是,如何使用 typeof 无法检查不存在的局部变量的“未定义”,但函数中声明的 let 变量却不能!所以这可能就是为什么我不会依赖 jQuery 来定义什么是最好的。 存在边缘情况

JavaScript 中“未定义”变量的更多怪异

**undefined 有两种不同的表达式和三种不同的用途,如下:

  1. “typeof”和“undefined”类型:未声明且不存在的变量不会被分配任何内容,但其“类型”为未定义。如果您访问一个甚至不存在的变量,更不用说声明或初始化了,那么您将在访问它时生成引用错误,即使在测试分配给声明的原始默认值 undefined 时也是如此变量直到被赋值。因此,在这种情况下检查“typeof”可以防止出现此错误,如下所示:
    // In this first test, the variable "myVariable1" does not exist yet so creates
    // an error if we try and check if its assigned the default value of undefined!
    if (myVariable1 === undefined) alert(true);// REFERENCE ERROR!

    // Here we can elegantly catch the "undefined" type 
    // of the missing variable and stop the REFERENCE ERROR using "typeof".
    if (typeof myVariable1 === "undefined") alert(true);// true

    // Here we have declared the missing variable and notice its 
    // still an "undefined" type until initialized with a value.
    let myVariable1;
    if (typeof myVariable1 === "undefined") alert(true);// true

    // Lastly, after we assign a value, the type is no longer 
    // "undefined" so returns false.
    myVariable1 = 'hello';
    if (typeof myVariable1 === "undefined") alert(true);// false

JavaScript 中访问但未声明的所有对象和类型都将默认为“未定义”类型。因此,这里的教训是首先尝试检查 typeof,以防止丢失变量错误!

  1. undefined 原始值:所有尚未赋值的声明变量在 JavaScript 中都被赋予 undefinedprimitve。如果您已声明变量,但尚未初始化它,则会为其分配默认的原始类型未定义。这与“未定义”类型不同。 undefined 的原始值是一个保留值,但可以更改,但这不是这里所要求的。请注意,这仅捕获所有已声明但未初始化的变量:
    let myVariable3;
    if (myVariable3 === undefined) alert(true);// true

    let myVariable4 = 'hello';
    if (myVariable4 === undefined) alert(true);// false
  1. 对象和未定义基元:最后,对象属性的行为与 JavaScript 中的变量不同。对象属性在丢失时不会变成未定义类型,而是简单地为未声明的变量分配原语 undefined。所以它们的行为就像#2:
    let myObject = {};
    if (myObject.myProperty === undefined) alert(true);// true

最佳实践

最后......这是始终检查“未定义”类型和未定义原始值的一个非常好的理由所有 JavaScript 代码中的变量。大多数人会说,你很少需要两者。可能有一天,在不存在的库中访问丢失的变量并创建令人讨厌的 JavaScript 引用错误!因此,我总是按照以下顺序执行此检查,以阻止 JavaScript 中的所有错误:

if (typeof myVariable !== "undefined" && myVariable !== undefined) {
    // do something safe with myVariable!
}

jQuery probably expects you to be using let and const variables in functions going forward, which in JavaScript's ES6 2015 design do NOT allow you to use any local scope (function) let or const variables until they are declared. Even hoisting by Javascript does not allow you to even type-check them!

If you try and do that, JavaScript generates an error, unlike with var variables which when hoisted creates a declared but uninitialized variable you can type check or check to see if its undefined.

If you declare a let or const variable in a function, but AFTER trying to access it, typeof checks still create a Reference Error in JavaScript! Its very odd behavior, and illogical to me why it was designed that way. But that is why jQuery likely sees no use for typeof function variable use. Example:

function MyError(){ 

    // WOW! This variable DOES NOT EVEN EXIST, but you can still check its type!
    if(typeof x === 'undefined')
    {
        alert(1);// OK!
    }

    // ERROR!
    // WOW! You cannot even check an existing "let" variable's TYPE in a local function!
    if(typeof y === 'undefined')//REFERENCE ERROR!!
    {
        alert(2);
    }
    // We defined the variable so its hoisted to the top but in a dead zone
    let y = 'test';
}

MyError();

// RESULT
// alert 1 fires but a REFERENCE ERROR is generated from the second alert 2 condition.

It is odd above how a non-existing local variable cant be checked using typeof for 'undefined', but a declared let variable in the function cannot! So this is likely why I would not depend on jQuery to define what is best. There are edge cases.

More Weirdness on "undefined" variables in JavaScript

**undefined has two different expressions, and three different uses, as follows:

  1. "typeof" and "undefined" types : Variables that are not declared and do not exist are not assigned anything, but have a "type" of undefined. If you access a variable that does NOT even exist, much less declared or initialized, you will generate a REFERENCE ERROR if you access it, even when testing for the primitive default value of undefined which is assigned to declared variables until assigned a value. So checking the "typeof" prevents this error in this one case as follows:
    // In this first test, the variable "myVariable1" does not exist yet so creates
    // an error if we try and check if its assigned the default value of undefined!
    if (myVariable1 === undefined) alert(true);// REFERENCE ERROR!

    // Here we can elegantly catch the "undefined" type 
    // of the missing variable and stop the REFERENCE ERROR using "typeof".
    if (typeof myVariable1 === "undefined") alert(true);// true

    // Here we have declared the missing variable and notice its 
    // still an "undefined" type until initialized with a value.
    let myVariable1;
    if (typeof myVariable1 === "undefined") alert(true);// true

    // Lastly, after we assign a value, the type is no longer 
    // "undefined" so returns false.
    myVariable1 = 'hello';
    if (typeof myVariable1 === "undefined") alert(true);// false

All objects and types in JavaScript that are accessed but not declared will default to a type of "undefined". So, the lesson here is try and check for the typeof first, to prevent missing variable errors!

  1. undefined primitive values : All declared variables not yet assigned a value are assigned in JavaScript the primitve of undefined. If you have declared a variable, but not initialized it yet, its assigned this default primitive type of undefined. That is not same as an "undefined" type. The primitive value of undefined is a reserved value but can be altered, but that's not what is asked here. Notice this catches all declared but uninitialized variables only:
    let myVariable3;
    if (myVariable3 === undefined) alert(true);// true

    let myVariable4 = 'hello';
    if (myVariable4 === undefined) alert(true);// false
  1. Objects and undefined primitives : Lastly, Object properties do NOT behave like variables in JavaScript. Object properties, when missing do not become undefined types, but are simply assigned the primitive undefined as above for undeclared variables. So they act like #2:
    let myObject = {};
    if (myObject.myProperty === undefined) alert(true);// true

BEST PRACTICE

Lastly....this is a VERY GOOD REASON to always check for BOTH the "undefined" type and the undefined primitive value on variables in all your JavaScript code. Most will say, you will rarely need both. There may come a day when a missing variable is accessed in a library that does not exist and creates a nasty JavaScript REFERENCE ERROR! So I always do this check, and in this order, to stop all errors in JavaScript:

if (typeof myVariable !== "undefined" && myVariable !== undefined) {
    // do something safe with myVariable!
}
烟柳画桥 2024-10-19 11:10:32

在节点 v6.9.1 上,typeof a === 'undefined'a === 'undefined' 快大约 2 倍。

typeof a === 'undefined' is faster then a === 'undefined' by about 2 times on node v6.9.1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文