Theoretical aspects
Semantically, undefined
means "without reference" and null
means "worthless". Or as placed by @Calebe Oliveira, "If any method returns undefined
, indicates that a certain property does not exist" and if it returns null
"the called property exists, but has no value". According to Wikipedia (free translation, emphasis mine):
In computing (in particular in programming), undefined value is a condition in which an expression does not have a correct value, although it is syntactically correct. An undefined value should not be confused with the empty string, the boolean "false" or other "empty" values (however defined). Depending on the circumstances, a resulting valuation at an indefinite value may cause an exception or undefined behavior, but in some programming languages undefined values may occur during the normal, predictable course of running a program.
Javascript does not use these concepts in this way, giving an accurate but rather distinct definition (as shown in the @bfavaretto quote from the Ecmascript specification), and some argue that the semantics of null
it is you who defines, according to your interpretation. The reason is that - when it comes to variables, the thing is much more complex - as shows the section dealing with references (free translation, emphasis mine):
A Reference is the resolution of a Binding name[-value]. A Reference consists of three components, the base value, the mentioned name and the reference flag "Strict" (boolean value). The base value is one of: undefined
, an object, a boolean, a string, a number, or a record of the [run] environment. An undefined base value indicates that the reference cannot be resolved in a Binding. The given name is a string.
That is, if an expression does not resolve itself in a Binding (i and.. the reference does not exist) its base value is undefined
and its access entails a ReferenceError
; if the reference exstir but has never been assigned, your value is undefined
. Already the null
also represents an "empty value", but only appears when explicitly defined as such - uninitialized variables will never have the value null
.
var a = 10, b = null, c;
console.log(a); // 10
console.log(b); // null
console.log(c); // undefined
console.log(d); // Uncaught ReferenceError: d is not defined
In practice
A number of practical aspects have been well addressed in the other replies, but I would like to complement them with the following observations::
Programmatically, it is not possible to distinguish between a property nonexistent and a worthwhile undefined
:
var x = {};
console.log(x.foo); // undefined
console.log(x); // Object {}
x.foo = undefined;
console.log(x.foo); // undefined
console.log(x); // Object {foo: undefined}
delete x.foo;
console.log(x.foo); // undefined
console.log(x); // Object {}
...unless is on its properties (or similar techniques, reflective):
for ( var p in x )
console.log(p); // Vai imprimir "foo" se x == Object {foo: undefined}
For this reason, care should be taken to use Duck Typing with objects that may have missing values (i.e. one should actually use null
to represent these values).
This difference is observed when an object is serialized in another format. For example, when mounting an Ajax request or converting to JSON format:
$.get(url, { foo:undefined, bar:null }); // http://example.com/?bar=
JSON.stringify({ foo:undefined, bar:null }); // {"bar":null}
This has practical importance because the code consumer of the serialized object can treat differently "missing property" and "missing value" (e.g.: Python launches a KeyError
when consulting a missing key in a dict
- but behaves normally when the key exists but its value is None
). So, if your object is sometime transmitted to an external system, it is important to use these types consistently and/or normalize the object before serialization (according to the desired behavior).
Often it’s more convenient utilise undefined
than null
, because one can express the absence of a value by the simple absence of code. Example:
function teste(obrigatorio, opcionais) {
var acc = obrigatorio;
acc -= (opcionais.foo || 1);
acc -= (opcionais.bar || 2);
acc -= (opcionais.baz || 3);
if ( acc >= 0 )
return acc;
}
var resultado = teste(10, { foo:20 });
if ( resultado ) { ... }
The "semantically correct" solution would be to return null
at the end of the function (instead of letting it implicitly return undefined
), besides passing the optional arguments as { foo:20, bar:null, baz:null }
. Admit the use of undefined
in these cases makes the code more concise, without any undesirable effects (unless it is clear that the results interact with external systems - as explained in the above item).
Mingle null
and undefined
does not cause so many problems, actually treating them as equal is quite easy (as quoted in passing in all other answers, but without delving into the subject). Sometimes it is not correct to test a value only as "truey" or "falsey" - for a value 0
, false
or the empty string (""
) is still considered a present value - so an explicit test is needed.
Meanwhile, as the operator ==
consider null
and undefined
equivalent (and nothing else), it is not necessary to test for both if the input mixes both. The example of the previous item (which could return zero as valid value) would be rewritten as:
var resultado = teste(10, { foo:20 });
if ( resultado != null ) { ... }
// ou
if ( resultado != undefined ) { ... }
(the first option is preferable - in addition to shorter, it is semantically more accurate, at least according to the intention of the code)
I’m wondering if I agree with some of the things you say. The specification is consistent with what she says, but not with her interpretation - which is great in practice, but it’s still an opinion. Ah, and the case of serialization you mentioned is important, if I may include an example of this in my reply.
– bfavaretto
Whether I agree or not, +1 for the beautiful answer!
– bfavaretto
@bfavaretto I will look for a quote that supports what I wrote (I guarantee it has not left my head). And feel free to improve your answer as much as you think necessary (I’m thinking of accepting it, because it is the most complete among those present).
– mgibsonbr
I’m very interested in this quote, if you think so. I said the specification is consistent but actually only I thought it was. I have now seen, for example, that
Object.getOwnPropertyDescriptor
returns Undefined to a property that does not exist, and an object (descriptor) to those that do exist. By definition, it should returnnull
- although it is possible to argue in favour of this choice by saying that the property itself is not defined.– bfavaretto
@bfavaretto I agree with your interpretation of the "Property Descriptor". As for my original argument, I have to arm myself: the semantics of the "undefined value" as described in Wikipedia (link in the edited answer) is one, the semantics used in the Ecmascript specification is another. And their behavior is quite inconsistent IMHO (ex.:
window.nao_existe
returnsundefined
, butnao_existe
spearReferenceError
, although this expression occurs in the top level, ie: a Variable Object the code itself Global Object!).– mgibsonbr
I don’t know if you noticed, but I posted window question.window because of the final part of his last comment. This inconsistent behavior only occurs because Enginers have chosen to expose the global object, but this is not a language requirement.
– bfavaretto