Reputation: 59351
The jQuery Core Style Guidelines suggest two different ways to check whether a variable is defined.
typeof variable === "undefined"
variable === undefined
object.prop === undefined
Why does jQuery use one approach for global variables and another for locals and properties?
Upvotes: 388
Views: 121158
Reputation: 34662
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.
Upvotes: 464
Reputation: 15957
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.
**undefined
has two different expressions, and three different uses, as follows:
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!
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
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
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!
}
Upvotes: -1
Reputation: 24370
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 ofundefined
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")
Upvotes: 34
Reputation: 36680
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.
undefined
var obj = {};
console.log(obj.myProp === undefined);
Upvotes: 2
Reputation: 165
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.
Upvotes: 6
Reputation: 27049
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.
Upvotes: 4
Reputation: 1
typeof a === 'undefined'
is faster then a === 'undefined'
by about 2 times on node v6.9.1.
Upvotes: -9
Reputation: 324737
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.
Upvotes: 144
Reputation: 2531
Who is interested in the performance gain of variable === undefined
, may take a look here, but it seems to be a chrome optimization only.
Upvotes: 6