Skip to content

逻辑或||的使用

x == 1 || x == 2 不能用 x == 1 || 2 表示

逻辑 ||(或运算)

  • 如果左操作数为真值,那么返回左操作数的值;
  • 如果左操作数为假值,那么返回右操作数的值;
  • 一旦遇到第一个真值,就会立即返回这个真值,并且不会继续计算后续的操作数。
js
console.log(true || 'hello');  // true
console.log(false || 'hello'); // 'hello'
console.log('hello' || true);  // 'hello'
console.log(0 || false) // false
console.log(true || 'hello');  // true
console.log(false || 'hello'); // 'hello'
console.log('hello' || true);  // 'hello'
console.log(0 || false) // false

应用:

js
let a = 1
let b = 0
let c = a || b
let d = b || a
console.log(c) // 1
console.log(d) // 0
console.log(Boolean(c)) // ture
console.log(Boolean(d)) // true
let a = 1
let b = 0
let c = a || b
let d = b || a
console.log(c) // 1
console.log(d) // 0
console.log(Boolean(c)) // ture
console.log(Boolean(d)) // true

应用:带括号的优先级

js
let a = 1
let b = 3
console.log(a === 1 || 2) // true,相当于 true || 2
console.log(a === 2 || 1) // 1,相当于 false || 1
console.log(b === 1 || 2) // 1,相当于 false || 2
console.log(a === (1 || 2)) // true,相当于a === 1
console.log(a === (2 || 1)) // false,相当于a === 2
console.log(b === (1 || 2)) // false,相当于b === 1
let a = 1
let b = 3
console.log(a === 1 || 2) // true,相当于 true || 2
console.log(a === 2 || 1) // 1,相当于 false || 1
console.log(b === 1 || 2) // 1,相当于 false || 2
console.log(a === (1 || 2)) // true,相当于a === 1
console.log(a === (2 || 1)) // false,相当于a === 2
console.log(b === (1 || 2)) // false,相当于b === 1

a == 1 || a == 2 可以写成 a == 1 || 2 吗?

JS中,a == 1 || a == 2 是正确的逻辑表达式,它检查 a 是否等于 1 或者等于 2。而 a == 1 || 2 是不正确的,因为它会先计算 a == 1,然后将结果与 2 进行逻辑或运算,这样的表达式没有意义。

逻辑 &&(与运算)

  • 如果左操作数为真值,那么返回右操作数的值;
  • 如果左操作数为假值,那么返回左操作数的值;
  • 一旦遇到第一个假值,就会立即返回这个假值,并且不会继续计算后续的操作数
js
console.log(true && 'hello');  // hello
console.log(false && 'hello'); // false
console.log(0 && false) // 0
console.log('hello' && true);  // true
console.log('hello' && false); // false
console.log(true && 'hello');  // hello
console.log(false && 'hello'); // false
console.log(0 && false) // 0
console.log('hello' && true);  // true
console.log('hello' && false); // false

应用:

js
let a = 1
let b = 0
let c = a && b
let d = b && a
console.log(c) // 0
console.log(d) // 0
console.log(Boolean(c)) // false
console.log(Boolean(d)) // false
let a = 1
let b = 0
let c = a && b
let d = b && a
console.log(c) // 0
console.log(d) // 0
console.log(Boolean(c)) // false
console.log(Boolean(d)) // false

应用:带括号的优先级

js
let a = 1
let b = 3
console.log(a === 1 && 2) // 2,相当于 (a === 1) && 2
console.log(a === 2 && 1) // false,相当于 (a === 2) && 1
console.log(b === 1 && 2) // false,相当于,相当于 false && 2
console.log(a === (1 && 2)) // false,相当于 a === 2
console.log(a === (2 && 1)) // true,相当于 a === 1
console.log(b === (1 && 2)) // false,相当于 b === 2
let a = 1
let b = 3
console.log(a === 1 && 2) // 2,相当于 (a === 1) && 2
console.log(a === 2 && 1) // false,相当于 (a === 2) && 1
console.log(b === 1 && 2) // false,相当于,相当于 false && 2
console.log(a === (1 && 2)) // false,相当于 a === 2
console.log(a === (2 && 1)) // true,相当于 a === 1
console.log(b === (1 && 2)) // false,相当于 b === 2

短路语法

js
// 常规写法
if (isLoggedIn) {
  goToHomepage()
}

// 简写
isLoggedIn && goToHomepage()
// 常规写法
if (isLoggedIn) {
  goToHomepage()
}

// 简写
isLoggedIn && goToHomepage()

逻辑运算符测试代码

js
{
    let a = 0;
    let b = 1;
    console.log(a && b); // 0
    console.log(a || b); // 1
  }

  {
    // && 的短路规则
    let a = 0;
    let b = 1;
    let c = 2;
    console.log(a && b); // 0
    console.log(b && a); // 0

    console.log(b && c); // 2
    console.log(c && b); // 1
    //   等同于

    let VariableOfFn = function (val) {
      console.log("函数被调用");
      return val;
    };

    a = 1;
    if (a === b) VariableOfFn(1); // &&右侧必须包含副效应(赋值、递增、递减或者幻术调用)的表达式
    a === b && VariableOfFn(1); // 只有a ===b时才调用函数,效果与上面一样
  }

  {
    // || 的短路规则
    let [a, b, c] = [0, 1, 2];
    console.info(0 || b); // 1
    console.info(b || 0); // 1
    console.info(b || c); // 1
    console.info(c || b); // 2
  }

  console.log(0 || 100 || 200);

  {
    // ! 操作符会将其操作数转换为布尔值,再将其反转为相反的布尔值
    // ! 操作符始终返回true或false
    // 要取得任何值x对应的布尔值,对其使用两次!!操作符极客
    // ! 操作符作为一元操作符,优先级较高
  }

  {
    // 德摩根定律
    let [q, p] = [0, 1];

    console.log('德摩根定律:', !(p || q) === (!p && !q))

    console.log('德摩根定律:', !(p && q) == (!p || !q))
  }
{
    let a = 0;
    let b = 1;
    console.log(a && b); // 0
    console.log(a || b); // 1
  }

  {
    // && 的短路规则
    let a = 0;
    let b = 1;
    let c = 2;
    console.log(a && b); // 0
    console.log(b && a); // 0

    console.log(b && c); // 2
    console.log(c && b); // 1
    //   等同于

    let VariableOfFn = function (val) {
      console.log("函数被调用");
      return val;
    };

    a = 1;
    if (a === b) VariableOfFn(1); // &&右侧必须包含副效应(赋值、递增、递减或者幻术调用)的表达式
    a === b && VariableOfFn(1); // 只有a ===b时才调用函数,效果与上面一样
  }

  {
    // || 的短路规则
    let [a, b, c] = [0, 1, 2];
    console.info(0 || b); // 1
    console.info(b || 0); // 1
    console.info(b || c); // 1
    console.info(c || b); // 2
  }

  console.log(0 || 100 || 200);

  {
    // ! 操作符会将其操作数转换为布尔值,再将其反转为相反的布尔值
    // ! 操作符始终返回true或false
    // 要取得任何值x对应的布尔值,对其使用两次!!操作符极客
    // ! 操作符作为一元操作符,优先级较高
  }

  {
    // 德摩根定律
    let [q, p] = [0, 1];

    console.log('德摩根定律:', !(p || q) === (!p && !q))

    console.log('德摩根定律:', !(p && q) == (!p || !q))
  }

逻辑运算符与短路规则

js
//逻辑 &&(与运算)
  console.log(true && 'hello');  // 'hello'
  console.log(false && 'hello'); // false
  console.log('hello' && true);  // true
  console.log('hello' && false); // false

  // 如果左操作数为真值,那么返回右操作数的值;
  // 如果左操作数为假值,那么返回左操作数的值。
  // 一旦遇到第一个假值,就会立即返回这个假值,并且不会继续计算后续的操作数

  // 逻辑 ||(或运算)

  console.log(true || 'hello');  // true
  console.log(false || 'hello'); // 'hello'
  console.log('hello' || true);  // 'hello'
  console.log('hello' || false); // 'hello'

  // 如果左操作数为真值,那么返回左操作数的值;
  // 如果左操作数为假值,那么返回右操作数的值。
  // 一旦遇到第一个真值,就会立即返回这个真值,并且不会继续计算后续的操作数

  let a = 1
  let b = 3
  console.log(a === 1 || 2) // true,相当于 true || 2
  console.log(a === 2 || 1) // 1,相当于 false || 1
  console.log(b === 1 || 2) // 1,相当于 false || 1
  console.log(a === (1 || 2)) // true,相当于a === 1
  console.log(a === (2 || 1)) // false,相当于a === 2
  console.log(b === (1 || 2)) // false,相当于a === 2


  console.log(a === 1 && 2) // 2,相当于 (a === 1) && 2
  console.log(a === 2 && 1) // false,相当于 (a === 2) && 1
  console.log(b === 1 && 2) // 2,相当于 (a === 1) && 2
  console.log(a === (1 && 2)) // false,相当于 a === 2
  console.log(a === (2 && 1)) // true,相当于 a === 1
  console.log(b === (1 && 2)) // false,相当于 a === 2
//逻辑 &&(与运算)
  console.log(true && 'hello');  // 'hello'
  console.log(false && 'hello'); // false
  console.log('hello' && true);  // true
  console.log('hello' && false); // false

  // 如果左操作数为真值,那么返回右操作数的值;
  // 如果左操作数为假值,那么返回左操作数的值。
  // 一旦遇到第一个假值,就会立即返回这个假值,并且不会继续计算后续的操作数

  // 逻辑 ||(或运算)

  console.log(true || 'hello');  // true
  console.log(false || 'hello'); // 'hello'
  console.log('hello' || true);  // 'hello'
  console.log('hello' || false); // 'hello'

  // 如果左操作数为真值,那么返回左操作数的值;
  // 如果左操作数为假值,那么返回右操作数的值。
  // 一旦遇到第一个真值,就会立即返回这个真值,并且不会继续计算后续的操作数

  let a = 1
  let b = 3
  console.log(a === 1 || 2) // true,相当于 true || 2
  console.log(a === 2 || 1) // 1,相当于 false || 1
  console.log(b === 1 || 2) // 1,相当于 false || 1
  console.log(a === (1 || 2)) // true,相当于a === 1
  console.log(a === (2 || 1)) // false,相当于a === 2
  console.log(b === (1 || 2)) // false,相当于a === 2


  console.log(a === 1 && 2) // 2,相当于 (a === 1) && 2
  console.log(a === 2 && 1) // false,相当于 (a === 2) && 1
  console.log(b === 1 && 2) // 2,相当于 (a === 1) && 2
  console.log(a === (1 && 2)) // false,相当于 a === 2
  console.log(a === (2 && 1)) // true,相当于 a === 1
  console.log(b === (1 && 2)) // false,相当于 a === 2

短路规则

可能看了这些,你的理解还不是很深刻,它到底可以帮我们怎么优化代码呢?

有以下几点是我们常用的:

1. 条件判断 &&

这个算是我们相当常见的使用了,可以用短路运算代替 if

js
if (condition) {
executeFunction();
}

//简化为
condition && executeFunction();
if (condition) {
executeFunction();
}

//简化为
condition && executeFunction();

在这个例子中,如果 condition 为 true,那么 executeFunction() 就会被执行;

如果 condition 为 false,那么由于 && 的短路性质,executeFunction() 就不会被执行。

2.默认值设置 ||

js
let value = possiblyUndefinedVariable || 'default value';
let value = possiblyUndefinedVariable || 'default value';

在这个例子中,如果 possiblyUndefinedVariable 为 undefined 或 null(或任何其他假值),那么 value 就会被设置为 'default value'。

在 JavaScript 中,"假值"(falsy value)是指在布尔上下文中被视为 false 的值。

假值在条件判断语句(如 if、while、for 等)或逻辑运算(&&、|| 等)中,会被自动转换为 false。其他所有的值都被认为是真值(truthy value),在布尔上下文中会被视为 true。

在 || 运算符中,如果左侧的值是假值,那么就会返回右侧的值。这常被用来为变量提供默认值:

3. 安全的对象属性访问:

在 JavaScript 中,如果你试图访问一个 undefined 或 null 的值的属性,会抛出 TypeError。

例如,如果 obj 是 undefined,则 obj.prop 会导致 TypeError。

在实际编程中,我们经常需要访问对象的嵌套属性,如 obj.prop.subProp,但在访问这些属性之前,我们可能并不确定 obj 或 obj.prop 是否存在。如果我们直接访问 obj.prop.subProp,而 obj 或 obj.prop 事实上是 undefined,那么就会抛出 TypeError。

为了避免这种错误,我们通常需要在访问嵌套属性之前检查每一级的对象是否存在。一种常见的做法是使用 && 运算符,如下所示:

js
let value = obj && obj.prop && obj.prop.subProp;
let value = obj && obj.prop && obj.prop.subProp;

在这个例子中,首先检查 obj 是否存在(即 obj 不是 undefined 或 null)。如果 obj 存在,那么就继续检查 obj.prop;如果 obj 不存在,那么 obj && obj.prop && obj.prop.subProp 的结果就是 undefined,并且由于 && 的短路特性,不会尝试访问 obj.prop。

同样,obj.prop && obj.prop.subProp 首先检查 obj.prop 是否存在。如果 obj.prop 存在,那么就返回 obj.prop.subProp;如果 obj.prop 不存在,那么就返回 undefined,并且不会尝试访问 obj.prop.subProp。

因此,使用 && 运算符可以避免在访问嵌套属性时由于中间的对象不存在而抛出的 TypeError。这就是所谓的"安全的对象属性访问"。

4. Optional Chaining (可选链)

在 JavaScript 中,我们经常需要检查一个对象是否有某个属性,然后再去获取那个属性的值。如果对象没有那个属性,我们通常需要提供一个默认值。

ES2020 引入了可选链(Optional Chaining)运算符 ?.,它提供了一种更简洁的方式来安全地访问深层次的对象属性。

例如,你可以写 let value = obj?.prop?.subProp; 来安全地访问 obj.prop.subProp,即使 obj 或 obj.prop 不存在,这也不会引发 TypeError 错误。如果 obj 或 obj.prop 不存在,那么表达式的结果就是 undefined。

js
let value = obj?.prop?.subProp || 'default value';
let value = obj?.prop?.subProp || 'default value';

在这个例子中,如果 obj 或 obj.prop 为 undefined 或 null,那么整个表达式的值就会是 'default value'。

5. Nullish Coalescing Operator (空值合并运算符)

JavaScript 在 2020 年引入了一个新的运算符 ??,它类似于 ||运算符,但只在左边的操作数为 null 或 undefined 时,才会返回右边的操作数。这对于处理可能为 0 或空字符串(它们在 JavaScript 中是假值)的值非常有用:

js
let value = possiblyZeroOrEmptyString ?? 'default value';
let value = possiblyZeroOrEmptyString ?? 'default value';

只有当 possiblyZeroOrEmptyString 为 null 或 undefined 时,value 才会被设置为 'default value'。

如果 possiblyZeroOrEmptyString 为 0 或空字符串,value 的值就会是 0 或空字符串。