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的逻辑运算符 || ,原因是只要理解了 && 的执行逻辑, || 的也就理解了,不是吗?


刘太刚
18 声望1 粉丝