[译] 怎样在 JavaScript 中检测 null

原文地址 : https://javascript.plainenglish.io/how-to-check-for-null-in-javascript-dffab64d8ed5
因为一些历史 bug, typeof null 在 JavaScript 中返回 object – 那么我们怎么检测 null 呢?

什么是 null ?

这个值 null 故意表现为没有任何值的对象, 这个是 Javascript 设计的初衷之一 – MDN Docs

Javascript 的基础类型 null 表示为故意设置的 - 来表示指示变量已被声明但尚未分配任何值。
null相比, 相似的值是 undefined, 没有任何对象的值, undefined是指的一个变量已经被声明但是没有赋值任何内容, 并不是 null值.
不幸的是 type of null永远返回 object, 这是一个永远不会修复的历史性的bug , 这就意味着不能够使用 typeof来验证 null值.

null 是一个 false 类型的值

null 是一个 值, (i.e. 也就是当他转换成 bool 类型时候, 会变成 false)” — Josh Clanton at A Drip of JavaScript

最简单的方法来检测 null值是把 null使用在条件变量中, null 会转换成 false进行条件运算

1
2
3
4
5
6
const maybeNull = null
if(maybeNull) { console.log("Not null") } else { console.log("Could be null") } // Could be null

for(let i = 0; null; i++) { console.log("Won't run") }

maybeNull ? console.log("truthy value") : console.log("Falsy value") // falsy value

当然这并不能表明 null其他 falsy 值 的差别, 接下来我们来探究下 =====在检测 null 值的区别

== 松散相等

“尽管事实上 null 是一个 [假] 值, 但是在 JavaScript 中并不能将这个值和其他的 [假] 值可以进行松散的相等, 事实上, nullundefined 和他自身可以松散相等” – Josh Clanton at A Drip of JavaScript

一个检测 null 的方法是将这个值和 null进行 ==(双等号) 比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
console.log("The 7 falsy values")
0 ? console.log("truthy") : console.log("falsy") // falsy
0n ? console.log("truthy") : console.log("falsy") // falsy
null ? console.log("truthy") : console.log("falsy") // falsy
undefined ? console.log("truthy") : console.log("falsy") // falsy
false ? console.log("truthy") : console.log("falsy") // falsy
NaN ? console.log("truthy") : console.log("falsy") // falsy
"" ? console.log("truthy") : console.log("falsy") // falsy

console.log("The value null")
console.log(null==0) // false
console.log(null==0n) // false
console.log(null==null) // true
console.log(null==undefined) // true
console.log(null==false) // false
console.log(null==NaN) // false
console.log(null=="") // false

像上边展示出来的结果似的, null 仅仅和他自身还有 undefined可以松散相等, 但是和其他的 [假] 值不等.
这对于检查值的缺失很有用 – nullundefined两者都表示没有值, 因此他们可以 松散相等(他们拥有相同的值, 但是类型不同).
所以我们写代码的时候如果要验证一个值是否存在值可以使用 == null 来检测他是 null 还是 undefined

=== 全等于

为了确认我们确实定义了一个 null 值, 而不是 undefined的值, 我们需要使用 ===(全等于) 来达到期望的效果

1
2
3
4
5
6
7
8
console.log("The value null")
console.log(null===0) // false
console.log(null===0n) // false
console.log(null===null) // true
console.log(null===undefined) // false
console.log(null===false) // false
console.log(null===NaN) // false
console.log(null==="") // false

通常来讲, 捕获 nullundefined是一个比较好的方式, 都代表的是没有值. 也就是说使用 ==来和 null 进行对比是 JavaScript 中为数不多的推荐的使用方式之一, 否则的话则使用 ===进行全等值的对比

检查 null 值时候使用 == 和 === 进行对比

有些开发者喜欢在任何情况下都使用 === 来进行清晰的对比, 所以也没有错啊.
确实在代码检查工具 JSLint 中不允许使用 ==因为类型强制来避免潜在的 bug 问题.
另一个代码检查工具 ESLint 则存在可以配置在什么情况使用 =====
也就是说如果你(或者检查工具) 习惯于使用 ===(全等于), 那么你可以使用 item === null || item === undefined来替代 ==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let maybeNull = null
// The following is equivalent to maybeNull == null or maybeNull == undefined:
console.log(maybeNull === undefined || maybeNull === null) // true
// Compare to the following:
console.log(maybeNull == null) // true
console.log(maybeNull == undefined) // true
console.log(maybeNull === null) // true
console.log(maybeNull === undefined) // false

maybeNull = undefined
console.log(maybeNull === undefined || maybeNull === null) // true
console.log(maybeNull == null) // true
console.log(maybeNull == undefined) // true
console.log(maybeNull === null) // false
console.log(maybeNull === undefined) // true

这样写比 == 操作符更清晰, 但是每个读代码的人都会清楚的知道检查了 null and undefined 两个值.

在现实世界中检测 null 的例子

“在实际使用过程中可能会出现这样的错误 [‘null is not an object’] , 这因为你在元素加载完成之前调用这个 dom 元素导致的, 因为 DOM API 在对象是空的情况下会返回 null“ – — Rollbar on the Top 10 JavaScript errors

如果是在加载 scirpt 之前尚未创建 dom 元素, 则会发生 TypeError (“null is not an object”) , 因为脚本的位置先于 html 元素出现, 而页面的解释则是从上到下的.
解决这个问题的办法是使用 event listener 来在页面加载完毕之后通知我们, 然后再运行脚本.
综上所述, 在尝试访问元素之前来检查 dom 元素是否为空是一个非常明智的做法.

使用 typeof 和 [假] 值检测

“庆幸的是,由于它不是真正的对象,它是唯一一个 [假]值的’对象’,空的对象都是 [真] 值” – — Casey Morris in Daily JS

另一个方法来检测 null 基于 null是 [假] 值, 但是空对象是 [真] 值, 所以 null是唯一一个 [假] 值的对象.
这可以很方便的使用 ! (非运算符) 来进行检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// The value null is the only falsy value with the typeof "object":
console.log(typeof null === "object" && !null) // true
console.log(typeof {} === "object" && !{}) // false

// This can be used to create a simple isNull() function:
const isNull = (value) => typeof value === "object" && !value
console.log(isNull(null)) // true

// To also check for an undeclared value, which will have typeof undefined, tweak the comparison slightly:
console.log(typeof maybeUndeclared === "undefined" || (typeof maybeUndeclared === "object" && !maybeUndeclared))
const isNullOrUndeclared = (value) => typeof value === "undefined" || (typeof value === "object" && !value))
const isNullOrUndeclared(undeclaredVariable) // true

// Otherwise, referencing an undeclared variable will throw a ReferenceError:
try { undeclaredVariable == null } catch(e) {
console.log(e)
} // ReferenceError: undeclaredVariable is not defined

使用 typeof是一个很有帮助的技巧, 因为一个变量未声明, 在引用的时候会抛出一个 ReferenceError
但是 typeof 一个未声明的变量结果是 undefined, 所以使用 typeof 是一个很好检测 null, undefined, 和未声明变量的方法.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// This will safely check a value to make sure it has been declared and assigned a value other than null or undefined:
console.log(typeof undeclaredVariable !== "undefined" &&
(typeof undeclaredVariable !== "object" || !undeclaredVariable)) // false

// Compare to checking for null using ==, which will only work for declared variables:
try { undeclaredVariable == null } catch(e) { console.log(e) } // ReferenceError: undeclaredVariable is not defined
try { undeclaredVariable === null } catch(e) { console.log(e) } // ReferenceError: undeclaredVariable is not defined
try { undeclaredVariable === undefined } catch(e) { console.log(e) } // ReferenceError: undeclaredVariable is not defined

let declaredButUndefinedVariable
// Values that have been declared but not assigned a value will have the value undefined, which has a typeof undefined:
console.log(typeof declaredButUndefinedVariable !== "undefined" &&
(typeof declaredButUndefinedVariable !== "object" || !declaredButUndefinedVariable)) // false

let stringVariable = "Here's Johnny!"
// If the variable has been both declared and assigned a value that is neither null or undefined, we will get true:
console.log(typeof stringVariable !== "undefined" &&
(typeof stringVariable !== "object" || !stringVariable)) // true

// This can be used to create a function that will return false for undefined, undeclared, and null values:
const isNotNullNorUndefined = (value) => typeof value !== "undefined" && (typeof value !== "object" || !value)
console.log(isNotNullNorUndefined(stringVariable)) // true

使用 Object.is()

ES6 函数 Object.is() 不同于 全等于 === 和 松散相等 ==的地方是检查 NaN-0
对于 null 来讲, Object.is()=== 结果一致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let maybeNull = null
// The following is equivalent to maybeNull == null or maybeNull == undefined:
console.log(Object.is(maybeNull,undefined) || Object.is(maybeNull,null)) // true
// Compare to the following:
console.log(maybeNull == null) // true
console.log(maybeNull == undefined) // true
console.log(maybeNull === null) // true
console.log(Object.is(maybeNull,null)) // true
console.log(maybeNull === undefined) // false
console.log(Object.is(maybeNull,undefined)) // false

maybeNull = undefined
console.log(maybeNull === undefined || maybeNull === null) // true
console.log(maybeNull == null) // true
console.log(maybeNull == undefined) // true
console.log(maybeNull === null) // false
console.log(Object.is(maybeNull,null)) // false
console.log(maybeNull === undefined) // true
console.log(Object.is(maybeNull,undefined)) // true

这意味着在使用 Object.is() 的时候需要严格检查 nullundefined, Object.is() 值在 React 中检查 state 变化的帮助方法.

总结

null 值检测是每一个 JavaScript 开发者在某个时候不许执行的常见任务
typeof null === 'object'意味着需要做更多的工作才能才能拿达到预期结果.
null === null 可以严格检查 null 值, null == undefined可以松散的检测null 或 undefined
null 是一个 [假] 值, 但是 空对象是一个 [真] 值, 所以 typeof maybeNull === "object" && !maybeNull 是一个比较简单的验证方式
最后, 如果检测一个值是不是已经声明了并且赋值, 但是
最后,要检查是否已声明值并分配了一个既不是 nullundefined 的值,请使用 typeof

1
typeof maybeUndeclared !== "undefined" && (typeof maybeUndeclared !== "object" || !maybeUndeclared)

下面可以放心的检查 null


语雀镜像 : [译] 怎样在 JavaScript 中检测 null ,点此 提问

作者

Duoli

发布于

2022-04-20

更新于

2022-09-28

许可协议

评论