DEV Community

Discussion on: What do we use null for in Js?

Collapse
peerreynders profile image
peerreynders • Edited on

Mozilla Developer Network (MDN):

Typically it's a good idea to have a look at the MDN Web Docs first when it comes to JavaScript and browser web APIs.

console.log(typeof null);      // "object"
console.log(typeof undefined); // "undefined"
Enter fullscreen mode Exit fullscreen mode

Now some people find this confusing but as MDN states:

null represents the intentional absence of any object value.

or put differently null is a reference that indicates the absence of an object where one might be expected.

However many developers have generalized null simply as the absence of any value (notice the absence of "object", so this includes primitive values) and go on to act on the convention to use null when they programmatically bind the absence of a value to a variable name.

The thing is that there are areas of JavaScript that don't play along with that perspective.

ES2015 introduced default parameters:

function addSome(one = 1, two = 2) {
  return (one ?? 0) + two;
}

console.log(addSome());             // 3 (1)
console.log(addSome(undefined, 4)); // 5 (2)
console.log(addSome(null, 4));      // 4 (3)
Enter fullscreen mode Exit fullscreen mode
  • (1): both arguments fall back to the default values so the result is 3
  • (2): both arguments are specified but one is undefined so the default value for one is used instead; so the result is 5
  • (3): both arguments are specified but one is null which does not fall back to the default value. Instead later the null is explicitly converted to to 0 using the nullish coalescing operator; so the result is 4.

This doesn't change even when we pass a default object:

function addSome(one = { a: 1 }, two = 2) {
  return (one?.a ?? 0) + two;
}

console.log(addSome());             // 3 (1)
console.log(addSome(undefined, 4)); // 5 (2)
console.log(addSome(null, 4));      // 4 (3)
Enter fullscreen mode Exit fullscreen mode

Optional Chaning

So when it comes to default parameters undefined represents the absence of any value - to be replaced with the default value.

Another example:

function show(array, index){
  console.log(array.hasOwnProperty(index), array[index]);
}

const values = [0,,undefined,3,null];

console.log(values.length); // 5
show(values, 1); // false, undefined
show(values, 2); // true, undefined
show(values, 4); // true, null

const others = new Array(5);

console.log(others.length); // 5
show(others, 0); // false, undefined
show(others, 4); // false, undefined
Enter fullscreen mode Exit fullscreen mode

values has a hole (or empty) at index 1 while there is an undefined value at index 2. Accessing either index with the bracket notation will result in an undefined value. Only hasOwnProperty(index) reveals that both are actually different, i.e. that there is an undefined value at index 2 while there is a missing (absent) value at 1.

Interestingly when specifying the arrayLength with the Array constructor a sparse array is created; that means that it isn't filled with undefined values but instead (conceptually) only consists of holes (empty values).

Now some people may take holes as a example of undefined being used to indicate "uninitialized" but undefined can be bound to any variable name just like any other primitive value.

Now if we divert to TypeScript for a moment there is the notion of optional parameters:

function f(x?: number) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

What is the type of x? It's number | undefined, i.e. either some number or undefined — but not null (because this needs to be consistent with how JavaScript default parameters behave).

Similarly there are optional properties:

interface PaintOptions {
  shape: Shape;
  xPos?: number;
  yPos?: number;
}
Enter fullscreen mode Exit fullscreen mode

Again the type of xPos and yPos is number | undefined. However here the property can be missing entirely (similar to an array hole) or it could exist with a value of undefined (though Exact Optional Property Types can disallow the undefined value and require an absent property instead).

Note that TypeScript's contribution guidelines state: "Use undefined. Do not use null".

Much earlier (2014) Douglas Crockford also argued against using null.

That said you will always encounter null.
Example Document.querySelector():

"Return value

An Element object representing the first element in the document that matches the specified set of CSS selectors, or null is returned if there are no matches."

querySelector() is expected to return an object. When no matching object is found the intentional absence of any object value is communicated with null.


Edit: Intent to stop using null in my JS