jQuery核心风格指南提供了两种不同的方法来检查变量是否被定义。

全局变量:typeof variable === "undefined" 局部变量:variable === undefined 属性:对象。Prop === undefined

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


当前回答

简介:

当处于全局作用域时,如果变量没有声明或值为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!
}

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

对于局部变量,使用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并不总是声明的,但是jQuery在它的main函数中声明了undefined。因此,它们在内部使用安全的未定义值,但在外部,它们使用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")