JS中逻辑运算符 && 的理解
从一个场景开始
我们试想这样一个场景,有这样一个对象,其数据结构为:
const obj = {
a: {
b: {
c: 'i am c'
}
}
}
要求是,写一个函数 printLast(value)
,将上述的对象的 obj.a.b.c
的值返回出来,否则,就返回 'nothing'
。
对于一个初学者,代码可能是这样的:
function printLast (obj) {
if (obj != null) {
if (obj.a != null) {
if (obj.a.b != null) {
if (obj.a.b.c != null) {
return obj.a.b.c
}
}
}
} else {
return 'nothing'
}
}
还有一种不太严谨的写法:
function printLast (obj) {
try {
if (obj.a.b.c != null) {
return obj.a.b.c
} else {
return 'nothing'
}
} catch (error) {
return 'nothing'
}
}
对于稍有经验的开发者,代码可能是这样的:
function printLast (obj) {
if (obj != null && obj.a != null && obj.a.b !=null && obj.a.b.c != null) {
return obj.a.b.c
} else {
return 'nothing'
}
}
或者
function printLast (obj) {
if (obj && obj.a && obj.a.b && obj.a.b.c) {
return obj.a.b.c
} else {
return 'nothing'
}
}
最后一种写法才是比较成熟的,但是其作者不一定知道 && 的执行逻辑。
步入正题
首先,我们回顾以下 && 的执行逻辑。
&& 的执行逻辑
官方的描述:
逻辑运算符通常用于布尔型(逻辑)值。这种情况下,它们返回一个布尔值。然而,&& 和 || 运算符会返回一个指定操作数的值,因此,这些运算符也用于非布尔值。这时,它们也就会返回一个非布尔型值。
大概的意思就是:&& 不仅可以用于布尔型的值,还可以用于非布尔值,并且返回的结果可以是任何类型的值,例如:
let bool = true && (3 === 4) // 返回值为 true
let bool = true && 'haha' // 返回值为'haha'
let bool = true && (() => { return 'haha' }) // 返回值为一个匿名函数: () => { return 'haha' }
这样的话,问题来了,什么样的值才能让 && 短路呢?
官方的描述,以下这些值能让 && 判断短路:
- null;
- NaN;
- 0;
- 空字符串("" or '' or ``);
- undefined。
例如:
let bool = 'haha' && 1 && null && true // 返回值为 null
let bool = 'haha' && 1 && 0 && true // 返回值为 0
let bool = 'haha' && 1 && '' && true // 返回值为 ''
除此之外的值,都会让 && 判断继续执行,直到最后一个值。
简单使用
根据上述,我们如何解决一开始的问题呢?答案是: 很简单,请看:
function printLast (obj) {
let res = obj && obj.a && obj.a.b && obj.a.b.c // 如果obj.a.b.c存在返回其值,否则,返回undefined
return !!res ? res : 'nothing'// !! 和 if 一样,能将各种类型的值转化为布尔量
}
或者
function printLast (obj) {
return (obj && obj.a && obj.a.b && obj.a.b.c) || 'nothing' // 如果obj.a.b.c存在返回其值,否则,返回'nothing'
}
因为 && 的执行是短路的, 所以当遇到undefined时,就会停止判断。
在这里,没有讨论js的逻辑运算符 || ,原因是只要理解了 && 的执行逻辑, || 的也就理解了,不是吗?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。