jQuery核心风格指南提供了两种不同的方法来检查变量是否被定义。
全局变量:typeof variable === "undefined" 局部变量:variable === undefined 属性:对象。Prop === undefined
为什么jQuery对全局变量使用一种方法,而对局部变量和属性使用另一种方法?
jQuery核心风格指南提供了两种不同的方法来检查变量是否被定义。
全局变量:typeof variable === "undefined" 局部变量:variable === undefined 属性:对象。Prop === undefined
为什么jQuery对全局变量使用一种方法,而对局部变量和属性使用另一种方法?
因为undefined并不总是声明的,但是jQuery在它的main函数中声明了undefined。因此,它们在内部使用安全的未定义值,但在外部,它们使用typeof样式以确保安全。
对于未声明的变量,typeof foo将返回字符串字面量“undefined”,而标识检查foo === undefined将触发错误“foo is not defined”。
对于局部变量(您知道在某处声明了),不会发生这样的错误,因此需要进行标识符检查。
我将坚持在任何地方使用typeof foo === "undefined"。这永远不会出错。
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.
以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检查。
使用typef -variant的另一个原因是:undefined可以被重新定义。
undefined = "foo";
var variable = "foo";
if (variable === undefined)
console.log("eh, what?!");
typeof变量的结果不能。
更新:注意,在ES5中不是这样的,全局未定义是一个不可配置,不可写的属性:
15.1.1全局对象的值属性 […] 15.1.1.3未定义 undefined的值是undefined(参见8.1)。该属性具有以下属性 {[[可写]]:false,[[可列举]]:false,[[可配置]]: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的性能增益感兴趣,可以在这里看看,但这似乎只是一个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未定义
下面是一些代码,可以澄清我上面所说的内容。为了更清晰,请注意内联注释。
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:
var globalVar1; //该变量声明了,但没有定义,因此值为undefined console.log(globalVar1 === undefined); //该变量未声明,因此将抛出referenceError console.log(globalVar2 === undefined);
因为在全局作用域中,我们不能100%确定是否声明了一个变量,这可能会给我们一个referenceError。当我们在未知变量上使用typeof操作符时,如果变量没有声明,就不会出现这个问题:
var globalVar1; log控制台。 log控制台。
这是因为typeof操作符在变量未声明或当前值为undefined时返回字符串未定义,而这正是我们想要的。
对于局部变量,我们就没有这个问题,因为我们事先知道这个变量是存在的。如果变量存在,我们可以简单地在相应的函数中查找。 对于对象属性,我们就没有这个问题,因为当我们试图查找一个不存在的对象属性时,我们也会得到undefined的值
var obj = {}; consoles.log(obj.myProp === undefined);
jQuery可能希望你在函数中使用let和const变量,在JavaScript的ES6 2015设计中,不允许你使用任何局部作用域(函数)let或const变量,直到它们被声明。甚至通过Javascript提升也不允许你对它们进行类型检查!
如果你尝试这样做,JavaScript会生成一个错误,不像var变量,当提升时创建一个声明但未初始化的变量,你可以输入检查或检查它是否未定义。
如果你在函数中声明了一个let或const变量,但是在尝试访问它之后,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检查'undefined',但函数中声明的let变量却不能!所以这可能就是为什么我不依赖jQuery来定义什么是最好的。有边界情况。
关于JavaScript中“未定义”变量的更多奇怪之处
**undefined有两种不同的表达式和三种不同的用法,如下所示:
"typeof"和"undefined"类型:未声明且不存在的变量没有被赋值,而是有一个"type"为undefined。如果你访问一个根本不存在的变量,更不用说声明或初始化了,如果你访问它,你会生成一个REFERENCE ERROR,即使是在测试原始的默认值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中所有被访问但未声明的对象和类型将默认为“undefined”类型。因此,这里的教训是首先尝试检查typeof,以防止丢失变量错误!
未定义的原始值:所有尚未赋值的声明变量都在JavaScript中被赋值为未定义的原语。如果你已经声明了一个变量,但还没有初始化它,它就会被赋值为默认的原始类型undefined。这与“未定义”类型不同。未定义的基本值是保留值,但可以更改,但这不是这里要求的。注意,这只捕获所有声明但未初始化的变量:
let myVariable3;
if (myVariable3 === undefined) alert(true);// true
let myVariable4 = 'hello';
if (myVariable4 === undefined) alert(true);// false
对象和未定义的原语:最后,对象属性的行为不像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!
}