null
in javascript is an object, which has few important, arguably confusing implications. Unfortunately JS has two ways to declare that something is "nothing", and the default way to do so is undefined
.
Having two ways to declare that something is "nothing" might be confusing and could be unnecessary. I can't come up with a use-case where I'd need two (and Douglas C. thinks the same), therefore we should pick one or another.
Below is why I think we should pick undefined
and not null
:
We have plenty of code like this:
// pretty common pattern to define default values
function foo(params) {
const x = params.x || 'default value'
console.log(x)
}
foo({x: null}) // default value
foo({x: undefined}) //default value
foo({}) //default value
Now you bravely moving to ES6 and love destructuring so you will happily refactor above to:
// pretty common pattern to define default values
function foo({x = 'default value'}) {
console.log(x)
}
Now can you guess what would be the output? If you can, awesome, I couldn't and when I explained it to a few friends, they were confused as well. It's somewhat non-intuitive:
foo({x: null}) // null
foo({x: undefined}) //default value
foo({}) //default value
it's even less intuitive if you would want to guard all your params against null
and undefined
// ES5
function foo(params) {
let myParams = params || {}
const x = myParams.x || 'default value'
console.log(x)
}
foo() // default value
foo(null) //default value
foo(undefined) //default value
//ES6+
function foo({x = 'default value'}) {
console.log(x)
}
foo() // exception is thrown
foo(null) //exception is thrown
foo(undefined) //exception is thrown
//Uncaught TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
so you can do this:
function foo({x = 'default value'} = {}) {
console.log(x)
}
foo() // "default value"
foo(null) //exception is thrown
foo(undefined) //"default value"
With last example our code is no longer safe, we need to additionally guard against null
or there is a chance to get a runtime exception. At the same time we have another "nothing" in the language that doesn't behave like an object and it would be "safe" to use it in this case.
I feel like this alone is a very strong 💪 argument against null
and for enabling corresponding eslint rule.
Few arguments from authority: TypeScript advices against null https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#null-and-undefined More details: https://basarat.gitbook.io/typescript/recap/null-undefined
Douglas Crockford also against null https://www.youtube.com/watch?v=PSGEjv3Tqo0&feature=youtu.be&t=9m21s
Lodash returns undefined
and not null
, e.g. _.find
and any other places where you would expect "null value".
@joebalancio yep, that's a good observation. Imo, it doesn't affect above arguments thought.