What is the difference between null and Undefined?

Asked

Viewed 18,382 times

42

Most programming languages have a "null" type to represent the absence of a value. It can have multiple names (null, nil, None, etc), but its purpose is the same (with the exception of SQL, where NULL means "unknown"). Javascript, however, has two distinct types: null and undefined.

What’s the difference between these two guys? I notice that they are not always used consistently (although in general they also mean no value), so it is difficult to know when to use one or the other. I know that a variable that has never been assigned is undefined - as well as a field not existing in an object - but I also know that it is possible to manually assign this value through var x = undefined; or obj.foo = undefined.

Is there any reason, in practice, to use one or the other? Or would it be better to use only one of them, and forget that the other exists (and if so, which)? Mixing the two in the same program seems to make it more difficult to treat cases of missing value... What would be the best approach in case this is out of your control? (i.e. external libraries/frameworks use one or the other type in the same script)

4 answers

39


Semantic difference

As already pointed out in the answers of Calebe Oliveira and of Alexandre Marcondes, there is a semantic difference between null and undefined: the value null is used to indicate the absence of a object, while undefined indicates the absence of any value. The specification makes this clear when setting the values undefined and null:

Undefined value

primitive value used when a variable had no value assigned

null value

primitive value representing the intentional absence of an object value

(Free translations)

The value returned by the operator typeof is consistent with this: it returns "object" for null, and "undefined" for undefined. The use of null in the specification also obeys this. For example, every object has an internal property [[Prototype]], whose value must be an object or null - never undefined. As mentioned by Caleb, the DOM Apis also make consistent use of this.

Syntactic differences

There are still syntactic differences between null and undefined. Both are the only values of their respective Types (Null and Undefined). However, null is also a reserved term and a literal grammar (such as true, 0, "" and /.*/), the Nullliteral, while undefined is exposed as a ownership of the global object, as well as NaN and Infinity.

Moreover, undefined is not a reserved term of language - which means, for example, that var undefined = "?" is a valid construct. Therefore, it is always possible to create a local variable called undefined whose value is not the primitive of the same name. This is not possible with null, var null = "?" generates a syntax error. In old language implementations it was also possible to override the global value undefined, but this is no longer permitted in Ecmascript 5, where the property undefined global object is defined as [[Writable]]:false, which means its value cannot be replaced.

In practice

The differences between null and undefined are subtle, but should be taken into consideration by programmers; ignoring them can give rise to bugs that are difficult to identify. In practice, always take into account the following:

  • In native variables, functions, properties and methods or host (provided by the environment, such as a browser) from which an object is expected as value or return, you will find null if an object is not present. It is recommended to follow this convention also in your own code.

  • Initialized variables that never had an assigned value contain the value undefined. Don’t forget that variable statements are always raised (hoisted) to the top of its scope, therefore:

    foo === undefined; // true
    var foo = 10;
    foo === 10; // true
    
  • Named function parameters that are not passed at call gain value undefined:

    (function(foo){
        foo === undefined; // true
    }());
    
  • undefined is the value returned when trying to read a nonexistent property of an object:

    var obj = {};
    obj.foo === undefined; // true
    
  • null and undefined are values falsey, that is, they are converted to false when forced to boolean:

    if(null || undefined) { /* nunca executa */ }
    !null === true; // true
    !undefined === true; // true
    
  • In comparisons of abstract equality (==) between two values, null and undefined are considered equivalent:

    null == undefined; // true
    undefined == null; // true
    

    Therefore, it is common to compare only with null to verify equivalence with either of the two:

    if(x == null) { /* x pode ser null ou undefined */ }
    
  • Comparisons of abstract equality (==) amid null or undefined and a value of another type always returns false. This is even valid for comparison with booleans:

    null == false; // false
    undefined == false; // false
    
  • When finding a reference to undefined in a code snippet, keep in mind that this is not a reserved term and may have been redefined:

    (function(undefined){
        undefined === window.undefined; // false
    }(10));
    
  • When an object is serialized with JSON.stringify, valuables undefined are not included in output (JSON does not have undefined). Therefore, if it is important to have the key to a property in the serialized output, it is best to use null to mark that it is empty:

    var o = {foo: undefined, bar: null };
    JSON.stringify(o); // {"bar": null} 
    
  • When transactions involving conversion of types are applied in null and undefined, the results may be different:

    null + 1; // 1
    undefined + 1; // NaN
    null + ""; // "null"
    undefined + ""; // "undefined"
    

14

The main difference is that undefined is the absence of something in the variable. It indicates that a variable has never been defined or that someone has assigned undefined to clear a variable. If you use typeof you will see that the object indicates to be of the type "undefined".

var a;
console.log(typeof a);                      //resultado> "undefined"

console.log(typeof a === "object");         //resultado> false 
console.log(typeof a === "undefined");      //resultado> true
console.log(typeof a == "undefined");       //resultado> true

Already the nullis a null value assigned to an object. It’s like you say it’s an object, but it hasn’t been initialized yet or it hasn’t been created. It is used to pass default values of uninitialized objects. If you use typeof you will see that the object indicates to be of the type "object".

var a = null;
console.log(typeof a);                      //resultado> "object"

console.log(typeof a === "undefined");      //resultado> false
console.log(typeof a === null);             //resultado> true
console.log(typeof a == null);              //resultado> true

Most of the time you can test using == so much for undefined how much for null which won’t make a difference, but if you want to make sure it’s something that hasn’t been assigned or if it’s an empty object you should check using === by the specific type. Simple comparison (==) compares only the value and, if necessary, converts the value to the type (case of strings and numbers) while strict comparison (===) compares the type and value, without converting it, if the type is not the same it returns false. See how they behave among themselves:

console.log(false == undefined);       //resultado> false
console.log(false == null);            //resultado> false
console.log(null == undefined);        //resultado> true
console.log(null === null);            //resultado> true
console.log(undefined === undefined);  //resultado> true
console.log(undefined === null);       //resultado> false
console.log(undefined == null);        //resultado> true

function test(val) {
    return val == null;
}
test(null);                            //resultado > true
test(undefined);                       //resultado > true

You can take advantage of this difference when checking by parameters in functions and some of them are optional. Parameters that have not been passed will be of value undefined and you can accept an empty object with null. Take an example:

function umaFuncao(primeiro, segundo, opcional) {
     if (typeof opcional === "undefined") {
        opcional = "três";
     }
    // faz algo
}

13

According to Ecmascript documentation, the value undefined is used when a variable does not have a value. The null is used when intentionally meaning that there is an absence of any object value for that variable.

A practical example is the call of methods or variables such as getElementById, childNodes[n], parentNode, etc., and they return null at some point. This means that the called property exists, but has no value, that is, there is no object associated with it. If any method returns undefined, indicates that a certain property does not exist.

Demonstration:

var x;

x == null            // true
x == undefined       // true
x === null           // false
x === undefined      // true (x não tem valor!)

var y = null;

y == null            // true
y == undefined       // true
y === null           // true
y === undefined      // false (y existe, e seu valor é null)

typeof x             // 'undefined'
typeof y             // 'object'

Examples from Soen.

7

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)

  • 1

    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.

  • Whether I agree or not, +1 for the beautiful answer!

  • @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).

  • 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 return null - although it is possible to argue in favour of this choice by saying that the property itself is not defined.

  • @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 returns undefined, but nao_existe spear ReferenceError, although this expression occurs in the top level, ie: a Variable Object the code itself Global Object!).

  • 1

    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.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.