Patrick McElhaney
Patrick McElhaney

Reputation: 59351

variable === undefined vs. typeof variable === "undefined"

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

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

Upvotes: 388

Views: 121158

Answers (9)

Linus Kleen
Linus Kleen

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

Stokely
Stokely

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.

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!
}

Upvotes: -1

Jakob
Jakob

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

Upvotes: 34

Willem van der Veen
Willem van der Veen

Reputation: 36680

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);

Upvotes: 2

Struppi
Struppi

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

CodingYoshi
CodingYoshi

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.

<== Fiddle Me ==>

Upvotes: 4

Eduard Popov
Eduard Popov

Reputation: 1

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

Upvotes: -9

Tim Down
Tim Down

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

RiZKiT
RiZKiT

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

Related Questions