Understanding JavaScript’s ‘undefined’

Compared to other languages, JavaScript’s concept of undefined is a little confusing. In particular, trying to understand ReferenceErrors (“x is not defined”) and how best to code against them can be frustrating.

This is my attempt to straighten things out a little. If you’re not already familiar with the difference between variables and properties in JavaScript (including the internal VariableObject) now might be a good time to check out my previous posting.

What is undefined?

In JavaScript there is Undefined (type), undefined (value) and undefined (variable).

Undefined (type) is a built-in JavaScript type.

undefined (value) is a primitive and is the sole value of the Undefined type. Any property that has not been assigned a value, assumes the undefined value. (ECMA 4.3.9 and 4.3.10). A function without a return statement, or a function with an empty return statement returns undefined. The value of an unsupplied function argument is undefined.

var a;
typeof a; //"undefined"

typeof window.b; //"undefined"

var c = (function() {})();
typeof c; //"undefined"

var d = (function(e) {return e})();
typeof d; //"undefined"

undefined (variable) is a global property whose initial value is undefined (value), Since its a global property we can also access it as a variable. For consistency I’m always going to call it a variable in this article.

typeof undefined; //"undefined"

var f = 2;
f = undefined; //re-assigning to undefined (variable)
typeof f; //"undefined" 

As of ECMA 3, its value can be reassigned :

undefined = "washing machine"; //assign a string to undefined (variable)
typeof undefined //"string"

f = undefined;
typeof f; //"string"
f; //"washing machine"

Needless to say, re-assigning values to the undefined variable is very bad practice, and in fact its not allowed by ECMA 5 (though amongst the current set of full browser releases, only Safari enforces this).

And then there’s null?

Yes, generally well understood but worth re-stating: undefined is distinct from null which is also a primitive value representing the intentional absence of a value. The only similarity between undefined and null is they both coerce to false.

So what’s a ReferenceError?

A ReferenceError indicates that an invalid reference value has been detected (ECMA 5

In practical terms, this means a ReferenceError will be thrown when JavaScript attempts to get the value of an unresolvable reference. (There are other cases where a ReferenceError will be thrown, most notably when running in ECMA 5 Strict mode. If you’re interested check the reading list at the end of this article)

Note how the message syntax varies across browser. As we will see none of these messages is particularly enlightening:

//FF/Chrome: foo is not defined
//IE: foo is undefined
//Safari: can't find variable foo

Still not clear…”unresolvable reference”?

In ECMA terms, a Reference consists of a base value and a reference name (ECMA 5 8.7 – again I’m glossing over strict mode. Also note that ECMA 3 terminology varies slightly but the effect is the same)

If the Reference is a property, the base value and the reference name sit either side of the dot (or first bracket or whatever):

window.foo; //base value = window, reference name = foo;
a.b; //base value = a, reference name = b;
myObj['create']; // base value = myObj, reference name = 'create';
//Safari, Chrome, IE8+ only
Object.defineProperty(window,"foo", {value: "hello"}); //base value = window, reference name = foo;

For variable References, the base value is the VariableObject of the current execution context. The VariableObject of the global context is the global object itself (window in a browser)). Each functional context has an abstract VariableObject known as the ActivationObject.

var foo; //base value = window, reference name = foo
function a() {
    var b; base value = <code>ActivationObject</code>, reference name = b

A Reference is considered unresolvable if its base value is undefined

Therefore a property reference is unresolvable if the value before the dot is undefined. The following example would throw a ReferenceError but it doesn’t because TypeError gets there first. This is because the base value of a property is subject to CheckObjectCoercible (ECMA 5 9.10 via 11.2.1) which throws a TypeError when trying to convert Undefined type to an Object. (thanks to kangax for the pre-posting tip off via twitter)

var foo;
foo.bar; //TypeError (base value, foo, is undefined)
bar.baz; //ReferenceError (bar is unersolvable)
undefined.foo; //TypeError (base value is undefined)

A variable Reference will never be unresolvable since the var keyword ensures a VariableObject is always assigned to the base value.

References which are neither properties or variables are by definition unresolvable and will throw a ReferenceError:

foo; //ReferenceError

JavaScript sees no explicit base value and therefore looks up the VariableObject for a property with reference name ‘foo’. Finding none it determines ‘foo’ has no base value and throws a ReferenceError

But isn’t foo just an undeclared variable?

Technically no. Though we sometimes find “undeclared variable” a useful term for bug diagnostics, in reality a variable is not a variable until its declared.

What about implicit globals?

It’s true, identifiers which were never declared with the var keyword will get created as global variables – but only if they are the object of an assignment

function a() {
    alert(foo); //ReferenceError
    bar = [1,2,3]; //no error, foo is global
bar; //"1,2,3" 

This is, of course, annoying. It would be better if JavaScript consistently threw ReferenceErrors when it encountered unresolvable references (and in fact this is what it does in ECMA Strict Mode)

When do I need to code against ReferenceErrors?

If your code is sound, very rarely. We’ve seen that in typical usage there is only one way to get an unresolvable reference: use a syntactically correct Reference that is neither a property or a variable. In most cases this scenario is avoided by ensuring you remember the var keyword. The only time you might get a run-time surprise is when referencing variables that only exist in certain browsers or 3rd party code.

A good example is the console. In Webkit browsers the console is built-in and the console property is always available. The Firefox console depends on Firebug (or other add-ons) being installed and switched on. IE7 has no console, IE8 has a console but the console property only exists when IE Developer Tools is started. Apparently Opera has a console but I’ve never got it to work ;-)

The upshot is that there’s a good chance the following snippet will throw a ReferenceError when run in the browser:

console.log(new Date());

How do I code against variables that may not exist?

One way to inspect an unresolvable reference without throwing a ReferenceError is by using the typeof keyword

if (typeof console != "undefined") {
    console.log(new Date());

However this always seems verbose to me, not to mention dubious (its not the reference name that is undefined, its the base value), and anyway I prefer to reserve typeof for positive type checking.

Fortunately there’s an alternative: we already know that undefined properties will not throw a ReferenceError providing their base value is defined- and since console belongs to the global object, we can just do this:

window.console && console.log(new Date());

In fact you should only ever need to check for variable existence within the global context (the other execution contexts exist within functions, and you control what variables exist in your own functions). So in theory at least you should be able to get away without ever using a typeof check against a ReferenceError

Where can I read more?

Mozilla Developer Center: undefined
Angus Croll: Variables vs. properties in JavaScript
Juriy Zaytsev (“kangax”): Understanding Delete
Dmitry A. Soshnikov: ECMA-262-3 in detail. Chapter 2. Variable object.
ECMA-262 5th Edition
undefined: 4.3.9, 4.3.10, 8.1
Reference Error: 8.7.1, 8.7.2, 10.2.1,,, and 11.13.1.
The Strict Mode of ECMAScript Annex C

15 thoughts on “Understanding JavaScript’s ‘undefined’

  1. FWIW, `undefined` is finally non-writable in ES5 (as well as global `NaN` and `Infinity` properties).

    Also, base value in property does not necessarily “sit” on the left side of a dot; it could also be to to the left of opening square bracket (as in `foo[bar]`).

    Finally, it’s good to understand that `foo.bar.baz` evaluates to a reference with `foo.bar` base and “baz” name (NOT `foo` base and name of whatever `bar.baz` evaluates to — I remember being confused about it in the past). This is due to grammar rules in ES, where `foo.bar.baz` is a /MemberExpression/ and is parsed as `MemberExpression . IdentifierName` (foo.bar — MemberExpression, baz — IdentifierName), which kind of unrolls /MemberExpression/ to the left side of `.` or `[`,`]` into its own `MemberExpression . IdentifierName` (until that something to the left is no longer a MemberExpression; but Identifier — `foo` — in this case).

    You could also test this easily with something like:

    var foo = { bar: { baz: function(){return this}}};
    foo.bar.baz() === foo.bar; // true

    1. kangax, thanks for pointing out the omissions (I did not know undefined is non writable in ES5 – not a moment too soon). Text updated with the first two points

  2. Another similarity between `undefined` and `null` is that `==` compares them equal to one another, which can also cause confusion. (But then we don’t use `==` any more, right?)

    `undefined` is such a nasty piece of work, causing difficult-to-debug problems by firing some time *after* you’ve made a mistake by accessing a non-existant property. Now the language has real exceptions and the `in` operator, this really should be changed to throw an exception immediately. Maybe for ECMAScript Sixth Edition `use “really strict”;` mode, eh?

  3. Regarding

    window.console && console.log(new Date());

    I think that works OK for some situations (although I personally find it ugly), but what if you have a property or variable that could have ”, 0, or null as a valid value?:

    function f (arg1, arg2, opts) {
    if (!opts.x) { ... } // This doesn't do what you want if 0 is a valid value for x

    I guess since you know the types your functions expect you can use either option as appropriate, but I’d rather be consistent and (almost) always use (typeof opts.x === 'undefined').

    1. Yeah its a case of understanding whether the expression makes sense and carries risk. console should never be zero or another falsey value and if it is it’s unusable anyway so the expression is sound. Obviously if your expression should process 0 or other falsey values than this style will fail. I’m not big on blanket rules – I prefer to code according to the nuance of the situation- it’s more communicative and often more efficient.

      Ultimately however it’s the choice of the developer based on his/her comfort level with both use case and language.

  4. window.console && console.log(new Date());
    I think it is better to test as:
    window.console && window.console.log(new Date());

    There is a possibility that the user has defined a variable in the current scope, so if you are testing it you should not assume “window.console” and “console” are the same.

    (function() {
    var console;
    })() //kaboom

    (function() {
    /*var console*/;
    })() //not kaboom

  5. “References which are neither properties or variables are by definition unresolvable and will throw a ReferenceError:
    foo; //ReferenceError
    JavaScript sees no explicit base value and therefore looks up the VariableObject for a property with reference name ‘foo’. Finding none it determines ‘foo’ has no base value and throws a ReferenceError”
    Why looks up the VO instead of Scope chain for a property?Could you explain that for me ,thanks.

  6. So what do I do if I get this message every time I try to type something. In plain language how does one fix it.

  7. Pingback: 核桃博客

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s