ES6查漏补缺【运算符的扩展】

前言:新年伊始,重走ES6之运算符的扩展。

运算符的扩展

一、ES6的扩展运算符

  • 作用:
    • 展开数组/字符串/对象
    • 复制(拷贝)数组/对象(浅拷贝)
    • 把伪数组转换为真数组
    • 函数的剩余参数

1.展开数组/字符串/对象

// 展开数组
const names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']
console.log(...names, '展开数组')  // Alice Bob Tiff Bruce Alice 展开数组

// 展开字符串
console.log(...'hello', '展开字符串')  // h e l l o 展开字符串

// 展开对象
const happy = {
    name: '高兴1',
    age: 12
}
console.log({ ...happy }, '展开对象') // {name: '高兴1',age: 12} 展开对象
实例
  • 求数组中最大和最小的值
//  求数组中最大和最小的值
const arr = [1, 5, 67, 87, 55, 32]
console.log('最大值为:', Math.max(...arr), '最小值为:', Math.min(...arr))

2.复制(拷贝)数组/对象

// 复制(拷贝)对象
const happy = {
    name: '高兴1',
    age: 25,
    children: {
        name: '不高兴',
        age: 5
    }
}
const why = { ...happy }
// 修改第一层
why.name = '开心'
console.log(why, '新数组')
console.log(happy, '原数组')

在这里插入图片描述

// 复制(拷贝)对象
const happy = {
    name: '高兴1',
    age: 25,
    children: {
        name: '不高兴',
        age: 5
    }
}
const why = { ...happy }
// 修改第二层
why.children.name = '不开心'
console.log(why, '新数组')
console.log(happy, '原数组')

在这里插入图片描述

小结:扩展运算符只能做到浅拷贝,拿过去的还是引用类型

3.合并数组/对象

合并数组
let arr1 = ['库里', '汤普森']
let arr2 = ['欧文', '杜兰特']

// ES5中
console.log(arr1.concat(arr2)) // ['库里', '汤普森', '欧文', '杜兰特']
// ES6中
console.log([...arr1, ...arr2]) // ['库里', '汤普森', '欧文', '杜兰特']
合并对象
const happy = {
    name: '高兴1',
    age: 25
}

const noHappy = {
    username: '不高兴',
    userage: 5
}

// 注意,对象里面的键值对名字不能相同,相同了后面的会覆盖前面的
const obj = {
    ...happy,
    ...noHappy
}
console.log(obj)

4.把伪数组 转为 真数组

function add() {
    console.log(arguments) // Arguments(5) [1, 2, 3, 4, 5, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    console.log([...arguments]) // [1, 2, 3, 4, 5]
}
add(1, 2, 3, 4, 5)

5.函数的剩余参数

// 如下简写,想象一下,如果传过来的是复杂对象或数组,对我们的用处会极大
function fn(one, ...nums) {
    console.log(one) // 1
    console.log(...nums) // 2 3 4 5
}
fn(1, 2, 3, 4, 5)

二、链判断运算符

//  普通情况
const obj = {
    name: 'KL',
    age: 20
}

// 把 obj.name 转为小写
console.log(obj.name.toLocaleLowerCase()) // kl

// 把 obj.nickname 属性值转为小写
console.log(obj.nickname.toLocaleLowerCase()) // 报错 因为obj.nickname为undefined
// 正确(安全)的做法
// 读取对象内部的某个属性,往往需要判断一下,属性的上层对象是否存在
if (obj.nickname) {
    console.log(obj.nickname.toLocaleLowerCase())
}

// 三元运算符 ? : 也常用于判断对象是否存在
const nickname = obj.naickname ? obj.nickname.toLocaleLowerCase : ''
console.log(nickname)
  • 以上的几种做法,都必须判断 obj.nickname 是否存在,才能转小写,这样的层层判断非常麻烦。
    当当当当,ES2020 中,引入了 链判断运算符,(opthional chaining operator) ?.,简化上面的写法。
console.log(obj?.nickname?.toLocaleLowerCase())

// 上述代码使用了 ?. 链判断运算符,直接在链式调用的时候判断
// 判断左侧的对象是否为 null 或 undefined,如果是,就不再往下运算,而是返回undefined
链判断运算符 ?. 有三种写法
1.obj.prop // 对象属性是否存在
2.obj?.[expr] // 同上
3.obj.func?.(...args) // 对象方法是否存在

// 注意事项:
// 短路机制:
// ?.运算符相当于一种短路机制,只要不满足条件,就不再往下执行

const obj = null
let a = 0

console.log(obj?.[++a]) // undefined
// 等同于
obj == null ? undefined : [++a]

小结:链判断运算符一旦为真,右侧的表达式就不再求值

Null 判断运算符

  • 作用:读取对象属性的时候,如果某个的值是null或undefined,就使用 ?? 后面的备用参数
  • 写法: ??
  • 例子: obj.name ?? ‘’
常规写法,不能实现(除非写死判断)
// 有时候需要为他们指定默认值。常见的做法是通过 || 运算符指定默认值
function add(options) {
    let x = options.x || 12
    let y = options.y || 30
    return x + y
}

// 上面的代码都通过 || 运算符指定的默认值,但是这样写是错的。开发者原意是
// 只要属性的值为null或undefined,默认值就会生效,
// 但是属性的值如果为 空字符串 或 false 或 0,默认值也会生效

console.log(add({ x: 33, y: 66 })) // 99
console.log(add({})) // 42
console.log(add({ x: 0, y: 0 })) // 42 有问题
console.log(add({ x: '', y: '??' })) // 12?? 有问题
使用ES6的Null运算符
function add(options) {
    let x = options.x ?? 12
    let y = options.y ?? 30
    return x + y
}

console.log(add({ x: 33, y: 66 })) // 99
console.log(add({})) // 42
console.log(add({ x: 0, y: 0 })) // 0
console.log(add({ x: '', y: '??' })) // ??

// 上面代码中,默认值只有在左侧属性值为null或undefined时,才会生效。
使用场景
  • 跟链判断运算符?.配合使用,来为null或undefined的值设置默认值
function add(options) {
    let x = options?.x ?? 12
    let y = options?.y ?? 30
    return x + y
}

console.log(add({ x: 1, y: 8 })) // 99
console.log(add()) // 42 如果没加链式运算的话 会报错
console.log(add({ x: 0, y: 0 })) // 0
console.log(add({ x: 'hello', y: '2022' })) // hello2022

注意事项:

  1. ! > && > ||
  2. ??本质上是逻辑运算,它与其他两个逻辑运算符 && 和 || 有一个优先级问题
  3. 它们之间的优先级到底孰高孰低。优先级的不同,往往会导致逻辑运算结果不同。
  4. 建议是,如果有多个逻辑运算符一起使用,必须用括号表明优先级,否则会报错。

指数运算符

  • 指数运算符: ** (不能有空格)
  • 指数赋值运算符: **=(写在一起的,不能有空格)
  • ~~:~是按位取反, ~~(取反再取反)在js中可以将浮点数变成整数,比parseInt快
指数运算符
// 需求:计算2的三次幂

// ES5
console.log(2 * 2 * 2) // 8
console.log(Math.pow(2, 3)) // 8

// ES6
console.log(2 ** 3) // 8
指数赋值运算符
let x = 3
// ES5
x = x * x * x * x
x = Math.pow(3, 4)

// ES6
x **= 4
console.log(x) // 81
按位取反运算符
// 两次 ~~ 取反取整
console.log(~~3.14) // 3
console.log(~~-3.14) // -3
console.log(~~0) // 0

逻辑赋值运算

  • ES2021 引入了三个新的逻辑赋值运算符(logical assignment operators)
  • 它们将逻辑运算符与赋值运算符进行结合
  • ||=: 或赋值运算符
  • &&=: 与赋值运算符
  • ??=: Null 赋值运算符
或赋值运算符
// 如果x为假,则把y的值赋给x
x ||= y
// 等同于
x || (x = y)
与赋值运算符
// 如果x为真,那么把y赋给x
x &&= y
// 等同于
x && (x = y)
Null 赋值运算符
// 如果x的值为null或undefined,就把y的值赋给x
x ??= y
// 等同于
x ?? (x = y)
用法
// 它们的一个用途是,为变量或属性设置默认值
// 老的写法
user.id = user.id || 1
// 新的写法
user.id ||= 1
function ajax(options) {
    options.method = options.method ?? 'get'
    options.dataType ?? (options.dataType = 'json')
}

// 上面示例中,参数对象options如果不存在属性method 和 属性 dataType
// 就为这两个属性设置默认值。有了 “Null 赋值运算符”以后,就可以统一写成下面这样

function ajax(options) {
    options.method ??= 'get'
    options.dataType ??= 'json'
}

相关资料


  • https://es6.ruanyifeng.com/
  • https://space.bilibili.com/510273162?spm_id_from=333.788.b_765f7570696e666f.2

水平有限,还不能写到尽善尽美,希望大家多多交流,跟春野一同进步!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值