【08】ES6:运算符的扩展

news/2024/5/18 13:17:10 标签: es6, udp, 前端

一、指数运算符

指数运算符(**)返回第一个操作数取第二个操作数的幂的结果。

x ** y

2 ** 2 // 4
2 ** 3 // 8

指数运算符是右结合的。

a ** b ** c 等于 a ** (b ** c)

2 ** 3 ** 2  // 相当于 2 ** (3 ** 2)  512

指数运算符可以与等号结合,形成一个新的赋值运算符(**=)。

let a = 1.5
a **= 2 // 等同于 a = a * a

let b = 4
b **= 3 // 等同于 b = b * b * b;

二、链判断运算符

链判断运算符(可选链运算符)?. 允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。

?. 运算符的功能类似于 . 链式运算符,不同之处在于,在引用为空的情况下不会引起错误,而是返回 undefined。(在链式调用的时候判断,左侧的对象是否为 null 或 undefined,如果是的,就不再往下运算,而是返回 undefined。)

// 错误的写法
const  firstName = message.body.user.firstName || 'default'

// && 运算符
const firstName = (message
	&& message.body
	&& message.body.user
	&& message.body.user.firstName) || 'default'

// ?: 三元运算符
const fooInput = myForm.querySelector('input[name=foo]')
const fooValue = fooInput ? fooInput.value : undefined

// .? 可选链运算符
const firstName = message?.body?.user?.firstName || 'default'
const fooValue = myForm.querySelector('input[name=foo]')?.value

链判断运算符 ?. 有三种写法

  • obj?.prop // 对象属性是否存在
  • obj?.[expr] // 同上
  • func?.(…args) // 函数或对象方法是否存在
// obj?.[expr] 用法:没有发现匹配返回 null,发现匹配返回一个数组
let hex = '#C0FFEE'.match(/#([A-Z]+)/i)?.[1]

a?.b
// 等同于
a == null ? undefined : a.b

a?.[x]
// 等同于
a == null ? undefined : a[x]

a?.b()
// 等同于(如果 a?.b() 里面的 a.b 有值,但不是函数,不可调用,那么 a?.b() 是会报错的。)
a == null ? undefined : a.b()

a?.()
// 等同于(如果 a 不是 null 或 undefined ,但也不是函数,那么 a?.() 会报错。)
a == null ? undefined : a()

注意点

(1)短路机制

本质上,?. 运算符相当于一种短路机制,只要不满足条件,就不再往下执行。

a?.[++x]
// 等同于
a == null ? undefined : a[++x]

上面代码中,如果 a 是 undefined 或 null ,那么 x 不会进行递增运算。也就是说,链判断运算符一旦为真,右侧的表达式就不再求值。

(2)括号的影响

如果属性链有圆括号,链判断运算符对圆括号外部没有影响,只对圆括号内部有影响。

(a?.b).c
// 等价于
(a == null ? undefined : a.b).c

上面代码中,?. 对圆括号外部没有影响,不管 a 对象是否存在,圆括号后面的 .c 总是会执行。

一般来说,使用 ?. 运算符的场合,不应该使用圆括号。

(3)报错场合

以下写法是禁止的,会报错。

// 构造函数
new a?.()
new a?.b()

// 链判断运算符的右侧有模板字符串
a?.`{b}`
a?.b`{c}`

// 链判断运算符的左侧是 super
super?.()
super?.foo

// 链运算符用于赋值运算符左侧
a?.b = c

(4)右侧不得为十进制数值

为了保证兼容以前的代码,允许 foo?.3:0 被解析成 foo ? .3 : 0,因此规定如果 ?. 后面紧跟一个十进制数字,那么 ?. 不再被看成是一个完整的运算符,而会按照三元运算符进行处理,也就是说,那个小数点会归属于后面的十进制数字,形成一个小数。

三、Null 判断运算符

Null 判断运算符 ??,又称空值合并运算符。是一个逻辑运算符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。

语法

leftExpr ?? rightExpr
const nullValue = null
const emptyText = '' // 空字符串,是一个假值,Boolean('') === false
const someNumber = 42

const valA = nullValue ?? 'valA 的默认值'
// valA 的默认值
const valB = emptyText ?? 'valB 的默认值'
// ''(空字符串虽然是假值,但不是 null 或者 undefined)
const valC = someNumber ?? 0
// 42

常见用途

(1)为变量赋默认值

读取对象属性的时候,如果某个属性的值是 null 或 undefined,有时候需要为它们指定默认值。常见做法是通过 || 运算符指定默认值。

逻辑或运算符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如,‘’ 或 0 或 false)时。

使用空值合并运算符 ??可以避免这种情况,只有运算符左侧的值为 null 或 undefined 时,才会返回右侧的值。

let myText = '' // An empty string (which is also a falsy value)

let notFalsyText = myText || 'Hello world'
console.log(notFalsyText) // Hello world

let preservingFalsy = myText ?? 'Hi neighborhood'
console.log(preservingFalsy); // '' (as myText is neither undefined nor null)

(2)与链判断运算符 ?. 配合使用为 null 或 undefined 的值设置默认值。

const animationDuration = response.settings?.animationDuration ?? 300

上面代码中,如果 response.settings 是 null 或 undefined ,或者 response.settings.animationDuration 是 null 或 undefined ,就会返回默认值 300。也就是说,这一行代码包括了两级属性的判断。

注意点

(1)短路机制

ORAND 逻辑运算符相似,当左表达式不为 null 或 undefined 时,不会对右表达式进行求值。

function A() {
	console.log('函数 A 被调用了')
	return undefined
}
function B() {
	console.log('函数 B 被调用了')
	return false
}
function C() {
  console.log('函数 C 被调用了')
  return 'foo'
}

console.log(A() ?? C())
// 依次打印 '函数 A 被调用了'、'函数 C 被调用了'、'foo'
// A() 返回了 undefined,所以运算符两边的表达式都被执行了

console.log(B() ?? C())
// 依次打印 '函数 B 被调用了'、'false'
// B() 返回了 false(既不是 null 也不是 undefined)
// 所以右侧表达式没有被执行

(2)优先级问题

?? 运算符 和其他逻辑运算符 &&|| 之间的运算优先级/运算顺序是未定义的,组合使用时,必须用括号表明优先级,否则会报错。

null || undefined ?? 'foo' // 抛出 SyntaxError
true || undefined ?? 'foo' // 抛出 SyntaxError

(null || undefined) ?? 'foo' // 返回 'foo'

四、逻辑赋值运算符

ES2021 引入了三个新的逻辑赋值运算符(logical assignment operators),将逻辑运算符与赋值运算符进行结合。

逻辑赋值运算符说明
||=逻辑或赋值运算符(x ||= y)运算仅在 x 为假值时为其赋值。等同于 x || (x = y)。
&&=逻辑与赋值运算符(x &&= y)运算仅在 x 为真值时为其赋值。等同于 x && (x = y)。
??=逻辑空赋值运算符(x ??= y)仅在 x 是空值(null 或 undefined)时对其赋值。等同于 x ?? (x = y)。

这三个运算符 ||=&&=??= 相当于先进行逻辑运算,然后根据运算结果,再视情况进行赋值运算。

用途:为变量或属性设置默认值。

user.id 属性如果不存在,则设为 1,新的写法比老的写法更紧凑一些。

// 老的写法
user.id = user.id || 1

// 新的写法
user.id ||= 1

参数对象 opts 如果不存在属性 foo 和属性 baz,则为这两个属性设置默认值。

function example(opts) {
	opts.foo = opts.foo ?? 'bar'
	opts.baz ?? (opts.baz = 'qux')
}

function example(opts) {
	opts.foo ??= 'bar'
	opts.baz ??= 'qux'
}

http://www.niftyadmin.cn/n/5261162.html

相关文章

react中MQTT的基础用法

MQTT是什么? MQTT基于发布/订阅范式的消息协议,工作在TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅消息协议,是一个基于客户端-服务端的消息发布/订阅传输协议。 在react中如何使用&am…

祝贺 年citation突破100

有好多年,写不出1篇论文了,也没有思路,觉得做的内容非常浅,一直忙于实际应用项目,偏技术突破。 2018出国访学后,重新看文献,整理思路,拓展思维,逐步写了几篇论文&#x…

初识GroovyShell

文章目录 前言一、GroovyShell二、maven三、解决方案四、关键代码4.1 数据库配置表(pg)4.2 入参4.3 分页查询 总结 前言 项目背景:查询多个表的数据列表和详情,但不想创建过多的po、dao、resp等项目文件。 一、GroovyShell Apache Groovy是一种强大的…

异步导入中使用SecurityUtils.getSubject().getPrincipal()获取LoginUser对象导致的缓存删除失败问题

结论 SecurityUtils.getSubject().getPrincipal()实际用的也是ThreadLocal,而ThreadLocal和线程绑定,异步会导致存数据丢失,注意! 业务背景 最近,系统偶尔会出现excel导入成功,但系统却提示存在进行中的…

【数据结构】哈希经典应用:布隆过滤器(哈希+位图)——[深度解析](9)

前言 大家好吖,欢迎来到 YY 滴 数据结构 系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 主要内容含: 欢迎订阅 YY滴 数据结构 专栏!更多干货持续更新!以下是传送门! 目录 一.布隆过滤器产生的…

Kotlin(十六) 高阶函数的简单应用

高阶函数非常适用于简化各种API的调用,一些API的原有用法在使用高阶函数简化之后,不管是在易用性还是可读性方面,都可能会有很大的提升。 所以我们可以通过高阶函数来使一些API变得更简单更易读。在我们APP存储数据时,通常会用到…

flink yarn-session 启动失败retrying connect to server 0.0.0.0/0.0.0.0:8032

原因分析,启动yarn-session.sh,会向resourcemanager的端口8032发起请求: 但是一直无法请求到8032端口,触发重试机制会不断尝试 备注:此问题出现时,我的环境ambari部署的HA 高可用hadoop,三个节点…

二蛋赠书十一期:《TypeScript入门与区块链项目实战》

前言 大家好!我是二蛋,一个热爱技术、乐于分享的工程师。在过去的几年里,我一直通过各种渠道与大家分享技术知识和经验。我深知,每一位技术人员都对自己的技能提升和职业发展有着热切的期待。因此,我非常感激大家一直…