SlightlyLoony
Tera Contributor

This past Monday I was at the inaugural meeting of our Federal Systems User Group (FSUG), where I had interesting conversations with several customers. In one of those conversations, we got to talking about developing on ServiceNow. An administrator (portrait at right) mentioned that while she had never used JavaScript before working with ServiceNow, she found the language generally easy to learn and use — except for one little area. "What," she asked "is the real difference between null and undefined? And what the #%*(*(@%$% is up with the == and ===, anyway?"

Well, my FSUG friend, this post's for you...

The notion of null is found in many programming languages, and usually by that name. Generally it indicates a reference to an object that happens to not refer to any object at the moment. The null is the absence of a reference in a reference. If you're of a certain age, you might naturally think of this as pointer containing a zero — a pointer that points to nothing. JavaScript's use of null is generally consistent with this, with one exception that I know of — if you execute a script like this:


var x = null;
var y = typeof x;
gs.log(y);

The result (which seems quite odd to me) is object. I don't know the real reason that JavaScript designers chose this result, but my guess is that they want developers to think of the null as an object that just happens to have no value.

Unlike many other popular programming languages, JavaScript lets you add properties to objects at runtime. That means that when any code gets an object value, it doesn't necessarily know what properties (including methods) it has. Consider this little snippet:

var x = {};
x.name = 'Hazel';
x.ssn = '123-45-6789';

var y = {};
y.name = 'Jeremy';
y.id = 'AX89 56E9 3HIE';

var z = {};
z.name = 'Horace';
z.ssn = null;

prettyPrint(x);
prettyPrint(y);
prettyPrint(z);

function prettyPrint(person) {
gs.log(person.name);
gs.log(person.ssn);
}

When prettyPrint() prints Hazel, we get both her name and SSN, because Hazel is a U.S. citizen. But when we go to print Jeremy (who is a citizen of Elbonia), he has no SSN — so what should print? That SSN property was never set in Jeremy's object — in JavaScript-speak, it was never defined. So if something was never defined, then it must be undefined — and hence that JavaScript concept. In fact, if you run the code above, undefined is exactly what's logged. The undefined value is actually implemented in JavaScript by a special Undefined object, which only has one instance (it's a singleton). Horace has an SSN property, because he's a U.S. citizen, but he forgot what it was — so we assigned a null for him (Horace is a null kinda guy, actually).

Note that difference between null and undefined: the former indicates that the property is there, but it doesn't refer to any value at the moment; the latter says the property isn't even there.

As a practical matter, most of the time we don't care whether something is null or undefined — we're going to behave the same way whichever it happens to be. Consider this small modification of the code above:

function prettyPrint(person) {
gs.log(person.name);
if (person.ssn != null)
gs.log(person.ssn);
}

If you run this code, you'll see that we skip printing either null or undefined, simply by testing it. If person.ssn is either null or undefined, the line won't print. Why? Because both of those values, when compared to null with !=, will return false. The == and != operators both treat null and undefined as if they were equivalent values.

But what if your code needs to behave differently based on whether a value was really undefined? That's where the === and !== operators come into play. Consider this:

function prettyPrint(person) {
gs.log(person.name);
if (person.ssn === undefined)
gs.log('No SSN, probably not a U.S. citizen');
else if (person.ssn === null)
gs.log('No SSN supplied');
else
gs.log(person.ssn);
}

The === (also called the identity operator) only returns true only if the two operands are exactly the same thing. Not the same value, but exactly the same object. The operator !== is exactly the inverse of this.

There's one peculiarity about the JavaScript implementation of undefined that's worth watching out for. It happens because undefined is actually an object. Check out this code:

var x = {};
x.y = undefined;
gs.log(x.y);
gs.log(x.z);

Both x.y and x.z log as undefined — but the x.y actually is defined. This ambiguity can happen because undefined is actually an object, and like any other object can be assigned to a property. If the property involved happens to be one that you created (and not an intrinsic property of the object), you can still tell them apart like this:

var x = {};
x.y = undefined;
gs.log(x.y);
gs.log(x.z);
gs.log(x.hasOwnProperty('y'));
gs.log(x.hasOwnProperty('z'));

The seldom-used hasOwnProperty() method is a built-in method of the Object class, so you can safely call it on any JavaScript object.

I'm pretty sure this is much more than my FSUG friend actually wanted to know...

4 Comments