368

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?

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Patrick McElhaney
  • 57,901
  • 40
  • 134
  • 167
  • I can't answer the question as to why JQuery would use both approaches, but Javascript does have some interesting quirks that mean these two things are subtly different. It shouldn't matter most of the time (ie if your code is sane), but there are differences nevertheless: See here for a write-up - http://wtfjs.com/2010/02/15/undefined-is-mutable – Spudley Jan 18 '11 at 15:13
  • 2
    As @Struppi pointed out, jQuery's outermost function has an argument named undefined. Within jQuery, `foo === undefined` is checking against the local copy of undefined instead of the global (window.undefined), which may have been modified by insane code. The fact that undefined is mutable is definitely worth noting and I'm glad you did. (+1) – Patrick McElhaney Jan 18 '11 at 15:36
  • 2
    Current link for that article is https://wtfjs.com/wtfs/2010-02-15-undefined-is-mutable – enigment Mar 31 '18 at 17:12

9 Answers9

441

For undeclared variables, typeof foo will return the string literal "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.

Linus Kleen
  • 33,871
  • 11
  • 91
  • 99
  • 4
    @goreSplatter You can't delete it now. :-) It was hard to choose, but the way the question is phrased, this answer is a better fit. Anyone who's interested in how undefined works in general (as I was) should also look at the other answers, especially @Tim's. – Patrick McElhaney Jan 18 '11 at 21:14
  • 4
    I would add quotation marks (`typeof foo; // -> "undefined"`) to emphasise it is a string and not the primitive value `undefined`. – c24w Apr 19 '13 at 16:06
  • I would add, checking for (x !== undefined) would also fail for local function variables, if you declared a "let" or "cont" type AFTER you tried to access it in a function. JavaScript hoists them, but they are in a dead zone, so even this would fail: function MyError(){ if(x !== undefined){console.log(x);} let x = 1;} MyError(); >>> "Uncaught ReferenceError: Cannot access 'x' before initialization." This forces developers to declare all their let/const variables at the top, but not after naive developers think they can check for the declared let in a local scope using (x !== undefined). – Stokely Feb 08 '23 at 19:22
142

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.

Linus Kleen
  • 33,871
  • 11
  • 91
  • 99
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • 12
    Thanks Tim. Your point about performance makes sense. The jQuery team is likely more concerned about the impact on file size. `foo === undefined`, when minimized, is probably something like `f===u`, whereas `typeof foo === "undefined"` can only be reduced to `typeof f==="undefined"`. – Patrick McElhaney Jan 18 '11 at 16:44
  • 1
    You could define `var u = "undefined"` and reduce it to `typeof f==u`, which improves things but is still larger. – Tim Down Jan 18 '11 at 16:57
  • 8
    Good points, but I'm not sure the safety of `typeof` against undeclared variables is an advantage. If anything it lets typos slip past more easily, and I can't see when you'd actually want to check the type of undeclared variables. – David Tang Jan 19 '11 at 12:03
  • 4
    @Box9: I can imagine using it in a library to check for the presence of another library. – Tim Down Jan 19 '11 at 12:18
  • 1
    @Tim Down, in which case `window.library === undefined` can be used (and the `window` should probably be explicit anyway). – David Tang Jan 19 '11 at 12:19
  • @Box9: Yes, that's true. I don't think I've ever needed to check for an undeclared variable, so I am struggling for use cases. – Tim Down Jan 19 '11 at 12:45
  • 1
    If you are using jslint it will not accept typeof variable === "undefined". – jontro Sep 26 '12 at 08:45
  • 3
    @jontro: That's one reason not to use JSLint then. – Tim Down Sep 26 '12 at 08:55
  • 1
    why did you write `BOOM` on `x.loadXml === undefined`? – Kevin Meredith Dec 26 '13 at 21:24
  • @KevinMeredith: A lighthearted way of saying that an error is thrown in Internet Explorer. I'll change it. – Tim Down Dec 26 '13 at 22:50
  • Thanks @TimDown. And it throws an error since that property `loadXml` is not a member of `x`, right? – Kevin Meredith Dec 26 '13 at 22:55
  • @KevinMeredith: Not exactly: for a native JavaScript object, accessing a non-existent property does not throw an error, but a host object (i.e. one provided by the environment such as a DOM node or ActiveX object) is not subject to the same rules and can do what it likes, inlcuding throwing an error for an innocent property access. The `loadXML` example illustrates this. – Tim Down Dec 26 '13 at 23:43
  • 1
    @TimDown If you check document.body.notDefined === undefined, it doesn't throw an error. – John Kurlak Mar 03 '14 at 19:21
  • @JohnKurlak: True, although I don't think I've implied that it would. – Tim Down Mar 03 '14 at 22:37
  • @TimDown You said, "evaluating a property of a host object for comparison can throw an error" – John Kurlak Mar 15 '14 at 05:06
  • 1
    @JohnKurlak: "can" being the operative word. – Tim Down Mar 15 '14 at 10:49
  • According to a quick test case I added on jsperf, saving the 'undefined' string in a variable `undef` and comparing with `typeof f == undef`, this is actually the slowest possible method amongst all listed. Not a good idea! [see jsperf](http://jsperf.com/type-of-undefined-vs-undefined/51) – yerforkferchips Aug 22 '14 at 07:17
  • @yerforkferchips: Yes, that's possible. However, speed of undefined checks is never going to be a serious concern in practice. Actually I do sometimes use direct comparison with `undefined` these days but not because of performance concerns. – Tim Down Aug 22 '14 at 11:10
  • 1
    It always depends on the use case, and you can never know about that in advance - so knowing about possible performance issues is good, right? :) – yerforkferchips Aug 22 '14 at 11:14
  • Both undefined and 'undefined' have falsy values in JavaScript, so a better way to determine this would be `!foo`, which would return a Boolean. – MadHatter Nov 20 '17 at 17:56
  • In older browsers undefined was mutable, ```undefined = 3``` ```console.log(undefined); // 3``` that's why jquery is declaring undefined. to make sure is always going to be undefined. ```(function (undefined) {console.log(undefined); /*undefined*/})();``` – ariel_556 May 10 '20 at 03:49
34

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")
t.niese
  • 39,256
  • 9
  • 74
  • 101
Jakob
  • 24,154
  • 8
  • 46
  • 57
  • 21
    Can’t be redefined in ES5. – Ry- Jul 10 '13 at 15:42
  • 7
    The global `undefined` property can't be redefined in ES5, but still can be shadowed with a local variable. `void 0` is shorter and safer. – Oriol Sep 13 '15 at 22:54
  • 1
    I'd say that if your code is redefining undefined then you have bigger problems to deal with than whether to use typeof or not. – chesscov77 Nov 10 '21 at 15:55
  • Yes, I agree, one's problems are bigger if the code is redefining undefined. But that is irrelevant wrt to the concept of Best Practices. – Adrian Bartholomew Aug 30 '23 at 15:36
6

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

RiZKiT
  • 2,107
  • 28
  • 23
6

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.

SherylHohman
  • 16,580
  • 17
  • 88
  • 94
Struppi
  • 153
  • 5
4

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 ==>

CodingYoshi
  • 25,467
  • 4
  • 62
  • 64
2

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);
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
-1

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!
}
Stokely
  • 12,444
  • 2
  • 35
  • 23
-8

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

CDspace
  • 2,639
  • 18
  • 30
  • 36
  • 6
    Those are not same things that you typed. I think you meant `undefined` at the second part, not `'undefined'` – scaryguy Feb 06 '19 at 03:51