likes
comments
collection
share

ECMAScript 新提案:有意思的逻辑赋值运算符

作者站长头像
站长
· 阅读数 1

最近,ECMAScript 增加了一个有趣的新提案,增加了如下三个复合赋值运算符:

  • a ||= b
  • a &&= b
  • a ??= b

详情参考:tc39.es/proposal-lo…

首先,我们看下当前已经有的运算符。

复合赋值运算符

JavaScript 当前已经支持的复合赋值运算符:

  • 基本算术运算符:+= , -= , *= , /= , %= , *=
  • 按位赋值运算符:&= , ^= , |=
  • 移位赋值运算符:<<= , >>= , >>>=

上面的复合运算符都是遵循如下的规则:

  • 表达式: a op= b
  • 等价于: a = a op b

比如: a &= b ===》 a = a & b

将 a 和 b 按位与,然后将结果赋值给 a

短路运算符

在我们尝试这次提议的复合运算符之前,我们需要先了解下 "短路运算符"。

逻辑运算符:|| , && , ?? 都是短路运算符,他们的第二个操作数都是依赖于第一个操作数不能得出结果的情况下才使用的:

运算符 等价于
a || b a ? a : b
a && b !a ? a : b
a ?? b a !== undefined && a !== null ? a : b

最新提案的逻辑运算符

新提案的逻辑运算符的表现和现有的复合运算符有点不一样:

赋值运算符 等价于
a ||= b a || (a = b)
a &&= b a && (a = b)
a ??= b a ?? (a = b)

为什么 a ||= b 是等价于 a || (a = b) 呢?

按照我们理解的短路运算符,应该等价于: a = a || b ,为啥不是这样的呢 ?

我们来看下这两者的差异:

  • a || (a = b): 这个表达是的意思是 只有当 a 为 false 的时候,才将 b 赋值给 a

  • a = a || b : 先将 a 赋值给 a ,然后再与 b 或运算。

综上,两者的意思有显著的差别。

接下来,我们来看下新提案的赋值表达式的可能的应用场景。

应用场景:使用 ??= 给对象增加缺少的属性

const books = [
  {
    isbn: '123',
  },
  {
    title: 'ECMAScript Language Specification',
    isbn: '456',
  },
];

// 给 books 的对象增加 title,如果没有 title 的情况下
for (const book of books) {
  book.title ??= '(Untitled)';
}
// 结果是相等的。
assert.deepEqual(
  books,
  [
    {
      isbn: '123',
      title: '(Untitled)',
    },
    {
      title: 'ECMAScript Language Specification',
      isbn: '456',
    },
  ]);

应用场景:使用 &&= 获取全局属性

const globalSettings = {
    title:'ECMAScript Language Specification',
    isbn:"456"
};
const params={
    title:true
}
// 给 params 设置全局属性,如果 params 需要获取哪个属性,则设置参数为 true即可。
for (const key of params) {
  params.key &&= globalSettings[key];
}
// 结果是相等的。
assert.deepEqual(
  params,
  {
      title:'ECMAScript Language Specification'
  }

应用场景:使用 ||= 分解表达式

如下函数,返回了一个跨多行展开的表达式:

function canContainNumber(value) {
  return typeof value === 'number'
    || typeof value === 'bigint'
    || typeof value === 'string'
  ;
}
assert.equal(canContainNumber(''), true);
assert.equal(canContainNumber(Symbol()), false);

上述函数可以写成如下:

function canContainNumber(value) {
  let result = false;
  result ||= typeof value === 'number';
  result ||= typeof value === 'bigint';
  result ||= typeof value === 'string';
  return result;
}