Thursday, July 24, 2008

Undeclared, Undefined, Null in JavaScript

So, a coworker of mine run into a situation recently where they were testing for an expression in JavaScript as:

if(obj.prop != null && obj.prop.subprop > 0) ...

This basically guards you against dereferencing "subprop" if "obj.prop" is itself undefined or null. They were running into a situation where the first predicate would pass, and the second would fail. However, "obj.prop" always printed "undefined". Turns out, it actually had the string "undefined" as its value.

Ouch.

Anyway, said coworker pointed me to a blog entry titled Three common mistakes in JavaScript / EcmaScript. Said blog entry says:

if (SomeObject != null) {

Well, in JavaScript, which is a dynamic language, something that has not been assigned to is not null, it's undefined. Undefined is different from null. Why? Don't ask me. Well, anyways, you can use typeof to explicitly check for undefined, or use other more or less clean tricks, but the best way to deal with that is probably to just rely on the type-sloppiness of JavaScript and count on it to evaluate null and undefined as false in a boolean expression, like this:

if (SomeObject) {

It looks uglier, but it's more robust.

I have to disagree. It's not more robust. It will also catch the cases of SomeObject having numeric value of 0, or string value of empty string. Because their boolean coercion is also false. To make matters worse, the original example, using SomeObject != null actually works and is in most cases actually the most appropriate!

See, in JavaScript, null and undefined are actually equal according to the == and != operator! (ECMA-262 standard, section 11.9.3 tells us so.) In vast majority of cases, you don't care about the difference at all, so using someExpr != null is good enough.

If you really-truly must distinguish between undefined and null, you have some options. Curiously, while there is an actual built-in language literal for the null value (namely, null), the sole value of the Null type, there is no built-in language literal for undefined, the sole value of the Undefined type. The identifier "undefined" can be assigned to, so you can't write something simple as if(x === undefined):

var undefined = "I'm defined now";
var x; // he's really undefined
print(x === undefined); // prints false


Inconvenient, huh? So, how to test for undefined? Well, the common practice found in most books and tutorials on JavaScript seems to be using the JS built-in typeof() function, but I really don't like it, because this is implemented by way of a string comparison:

var x;
print(typeof(x) == "undefined");


will actually print true. But as I said, I think it's ugly.

My solution instead relies on the fact that undefined is equal to null, but is not strictly equal to null, therefore this expression also works:

var x;
print(x == null && x !== null);


will also print true, and it involes only two simple comparisons.

Which brings us to the question of what is the actual difference in JavaScript between an undeclared variable, a variable with undefined value, and a variable with null value. Let's see:

var x = {}; // empty object
var u; // declared, but undefined
var n = null; // declared, defined to be null

function isUndefined(x) { return x == null && x !== null; }

print(isUndefined(x.x)); // prints true - access to undefined property on an object yields undefined
print(isUndefined(u)); // prints true - declared, but undefined value
print(isUndefined(n)); // prints false - the value is null, not undefined
print(isUndefined(z)); // runtime error -- z is undeclared


So, it's an error to dereference an undeclared variable, "z" in above example (it's okay to assign to it, which creates a new global variable). It is not an error to dereference a declared variable with undefined value, "u" in above example. Its value is the undefined value. Further, access to any undefined properties on objects also result in undefined value, duh. As for null, well, null is just a value like true, or false, or 4.66920166091; it's the single value of the type Null.

Hope this clears up the whole topic of undefined/null values (and undeclared variables) somewhat.

13 comments:

Unknown said...

Thanks for correcting me. I fixed my post.

Anonymous said...

Just some notes:
[=] undefined is a JavaScript reserved word.
So not good to use it as a variable name.
// not good
var undefined = "I'm defined now";

[=] undefined can be compared
we can use operator like == and === and != and !==

var x; // he's really undefined
alert(x === undefined); // true

No need to use the typeof operator or write a function.

Attila Szegedi said...

It's a common misconception, but you are wrong; "undefined" is not a reserved word in JavaScript.

Ates Goral said...

Note that typeof is not function; it's an operator. When you write:

typeof(x) == "undefined"

It works due to the same reason "return (x)" works; you're simply enclosing the unary expression in parenthesis; you're not really making a function call. To be pedantic, it's better to write:

typeof x == "undefined"

Matt said...

"Concur" means the opposite of what you think it means. http://en.wiktionary.org/wiki/concur

Attila Szegedi said...

@Matt: you're right; good catch - I'll fix the article. Thanks.

Donavon West said...

Thanks for your solution. However I use Douglas Crockford's JSLint on everything I release (a good habit to get into) and your code does not pass the "don't use == on a null" check.

A better function (keeping JSLint in mind) would be what I now have in my js library:

function isUndefined(x) {var u; return x === u;}

Thanks,
Donavon

Attila Szegedi said...

Thanks Donavon, that indeed looks like a great solution.

HB said...

Excellent solution(s) for finding out if something is truly undefined. Thanks for this post!

Anonymous said...

According to Mozilla developer network, 'undefined' is a property of the global object. It is not a reserved word, but comparison with it is possible.
MDN on undefined

Unknown said...

I have and Undefined return value!! why!? =(

function readFromExcel(x,y)
{
excel = null;
book = null;
sheet = null;
data = null;
var excel = new ActiveXObject("Excel.Application");
var book = excel.Workbooks.Open("http://142.116.39.71/Planeacion/hoja.xlsx");
var sheet = book.Worksheets.item(1);
var data = sheet.Cells(x,y).Value;
return data;
excel.quit();
excel.application.quit();
CollectGarbage();

}
function readVal()
{
var val=null;
val = readFromExcel(5,18);
document.write(val);
print(val)
}
readVal();

Anonymous said...

A good example to not to use == and != instead use === and !==. I highly recommend the use of jslint and the book javascript the good parts.

Jason Sebring said...

var getType = function(thing) {
if (typeof thing === 'undefined'){
return 'undefined';
}
if (thing === null) { return 'Null';}
return thing.constructor.name;
}

// but you could improve it maybe