320

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
  • 7,720
  • 5
  • 40
  • 66
Patrick McElhaney
  • 52,844
  • 37
  • 123
  • 157
  • 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
  • 1
    Current link for that article is https://wtfjs.com/wtfs/2010-02-15-undefined-is-mutable – enigment Mar 31 '18 at 17:12

8 Answers8

392

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
  • 31,276
  • 11
  • 85
  • 97
  • 3
    @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
126

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
  • 31,276
  • 11
  • 85
  • 97
Tim Down
  • 292,637
  • 67
  • 429
  • 506
  • 10
    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
  • 6
    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
  • 3
    @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
  • If you are using jslint it will not accept typeof variable === "undefined". – jontro Sep 26 '12 at 08:45
  • 2
    @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
  • @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
32

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
  • 32,069
  • 7
  • 56
  • 86
Jakob
  • 23,205
  • 7
  • 44
  • 55
  • 18
    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
8

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
  • 12,507
  • 16
  • 70
  • 78
Struppi
  • 105
  • 3
7

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
  • 1,280
  • 18
  • 16
2

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
  • 21,881
  • 3
  • 45
  • 51
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
  • 19,609
  • 11
  • 116
  • 113
-5

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

CDspace
  • 2,551
  • 17
  • 31
  • 35
  • 3
    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