JS操作符

140 阅读3分钟

运算符(operator)也被称为操作符,是用于实现赋值、比较和执行计算数运算等 功能的符号

常用的运算符有: 算数运算符、递增和递减运算符、比较运算符、逻辑运算符、赋值运算符

1. 算数运算符

1.1 概述:算术运算使用的符号,用于执行两个变量或值的算术运算

  • +:加 10 + 20 = 30
  • -: 减 10 -20 = -10
  • *: 乘 10 * 20 = 200
  • /: 除 10 / 20 = 0.5
  • %: 取余数(取模) 9 % 2 = 1返回除法的余数

1.2 浮点数的精度问题

  • 浮点数值的最高精度是17位小数,但是在运行算术时其精度远远不如整数
// 浮点数 算数运算里面会有问题
console.log(0.1 + 0.2); //0.30000000000000004
console.log(0.07 * 100);//7.000000000000001
  • 不要直接判断两个浮点数是否相等
var num = 0.1 + 0.2
console.log(num == 0.3) // false

1.3 表达式和返回值

  • 表达式:是由数字、运算符、变量等以能求得数值的有意义排列方法所得的组合
  • 表达式最终都会有一个结果,返回给我们,我们称为返回值
// 是由数字、运算符、变量等组成的式子 称为表达式 1+1
console.log(1 + 1); //2就是返回值
// 1+1=2
// 在程序里面2=1+1 把右边表达式计算完毕把返回值给左边
var num = 1 + 1;
console.log(num);//2

2. 递增和递减运算符

2.1 概述

  • 如果需要反复给数字变量加或者减去1,可以使用递增(++)和递减(--)运算符来完成
  • 在JS中,递增(++)和递减(--)既可以放在变量前面也可以放在变量后面
  • 放在变量前面时,可以称之为前置递增/递减运算符
  • 放在变量后面时,可以称之为后置递增/递减运算符

2.2 前置递增/递减运算符

  • ++num前置递增,就是自加1,类似于 num = num + 1
var n = 10; n = n + 1; console.log(n) // 11
var m = 10; ++m; console.log(m) // 11
  • **注意:**先加1,后返回值 var n = 10; console.log(++n + 10)// 21

2.3 后置递增/递减运算符

  • num++ 后置递增,就是自加1,类似于num = num + 1
  • 前置自增和后置自增如果单独使用,效果是一样的
var n = 10; n++; console.log(n) // 11
var m = 10; console.log(m++ + 1); // 20 console.log(m)// 11 
  • 注意先返回值,再加1 var a = 10; a++; var b = a++ + 2; console.log(b)// 13

2.4 前置递增和后置递增小结

  • 前置递增和后置递增运算符简化代码的编写,写法更简单
  • 单独使用时运算结果相同
  • 与其他代码连用时,执行结果会不同
  • 前置:先自加,后运算(先己后人)
  • 后置:先原值运算,后自加(先人后已)
  • 开发时,大多使用后置递增/递减,代码独占一行

3. 比较运算符

3.1 概述:比较运算符(关系运算符)是两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值

  • <: 小于号, 1 < 2; // rue
  • >: 大于号, 1 > 2; // false
  • >=: 大于等于号(大于或等于),2 >= 2; // true
  • <=: 小于等于号(小于或者等于),3 <= 2; // false
  • ==: 判等号(会转型), 37 == '37'; // true
  • !=: 不等号,37 != '37'; // false
  • ===: 全等, 要求值和数据类型都一致, 37 === '37';// fslse
  • !==: 全不等, 要求值和数据类型都不一致, 37 !== '37';// true

3.2 =小结

  • =: 赋值,把右边给左边
  • ==: 判断,判断两边的值是否相等(注意此时有隐式转换)
  • ===: 全等,判断两边的值和数据类型是否完全相等

4. 逻辑运算符

4.1 概述:逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值,开发中常用于多个条件的判断

4.2 &&: 逻辑与,简称与 and,true && false

  • 两边都是true才返回true,否则返回false

4.3 ||: 逻辑或,简称或 or, true || false

  • 两边都为false才返回false,否则都为true

4.4 !: 逻辑非,简称非 not, !true

  • 逻辑非!,也叫取反符,用来取一个布尔值相反的值,如true的取反值是false

4.5 ?.: 可选链操作符

  • 当你访问某个对象的属性或者调用某个属性上的方法时,如果这个对象的值为undefined或者null,那么语句执行就会报错
  • 以往我们加一层判断来确保访问的对象不为undefined或者null,然后才做后续操作,繁琐不够优雅
  • ?.作用就是如果对象的属性值为undefined或者null时候,不做后续操作
let obj = {
    step1: {
        name: '步骤一',
        step2: {
            name: '步骤二'
        }
    }
}
// 如果访问step2的name属性,即obj.step1.stpe2.name
// 为了确保安全性,以前我们可能要写如下代码
if(obj && obj.step1 && obj.step.step2 && obj.step1.step2.name) {
    obj.step1.step2.name.toString()
}
// 用可选链的话
obj?.step1?.step2?.name?.toString()

4.6 ??: 控制合并操作符

  • 这是一个逻辑操作符,与||操作符十分相似,但是并不是等价的
let a = 0
let b = ''
let c = null
let d = undefined

let x = a ?? 100 // x 等于 0
let y = b ?? 100 // y 等于 ''
let z = c ?? 100 // z 等于 100
let k = d ?? 100 // k 等于 100

let o = a || 100  // o 等于 100
let p = b || 100  // p 等于 100
let q = c || 100  // q 等于 100
let r = d || 100  // r 等于 100
  • ??只有当操作符左侧表达式的值为undefined或者null时,才会返回右侧的值
  • ||只要操作符左侧表达式的值为false时,就会返回右侧的值。左侧的表达式会自动做布尔运算,因为0和空字符串做布尔运算为false

4.7 ??=: 空值赋值操作符

  • 只有当??=左侧的值为null或者undefined的时候,才会将右侧变量的值赋值给左侧变量,其他所有值都不会进行赋值
let a = null
let b = undefined
let c = 100
let d = 200

a ??= c // a = 100
// 因为 a 的值为 null,所以会将 c 的值赋值给 a , 所以最终 a = 100

b ??= d // b = 200
// 因为 b 的值为 undefined,所以会将 d 的值赋值给 b , 所以最终 b = 200

4.8 _数值分割符

  • ES2021引入数值分隔符_,在数值组之间提供分割,使一个长数值读起来更容易,Chrome已经提供了对数值分隔符的支持
let number = 100_0000_0000_0000 // 0太多了不用数值分割符眼睛看花了 
console.log(number) // 输出 100000000000000
  • 十进制的小数部分也可以使用数值分隔符,二进制、十六进制也可以使用数值分隔符
0x11_1 === 0x111 // true 十六进制 
0.11_1 === 0.111 // true 十进制的小数 
0b11_1 === 0b111 // true 二进制

4.9 ,:逗号运算符

  • 逗号操作符对它的每个操作数求值(从左到右),并返回最后一个操作数的值
  • expr1, expr2, expr3...: 会返回最后一个表达式expr3的结果,其他表达式只会进行求值

4.10 #:私有方法/属性

  • 在一个类里面可以给属性前面增加#私有标记的方式来标记为私有,getter/setter也可以标记为私有,方法也可以标记为私有
class Person {
    getDesc() { return this.#name + '' + this.#getAge()}
    #getAge() { return this.#age } // 私有方法
    get #name() { return 'foo' } // 私有访问器
    #age = 22 // 私有属性
}
const a = new Person()
console.log(a.age) // undefined 直接访问不到
console.log(a.getDesc()) // foo 22 

5. 赋值运算符

function reverse(arr) {
    return [arr[0], arr[1]]=[arr[1], arr[0]], arr[0] + arr[1]
}
const list = [1, 2]
reverse(list)   // 返回 3,此时 list 为[2, 1]

5.1 用来把数据赋值给变量的运算符

  • =: 直接赋值,var a = '我是值'
  • +=、-=: 加、减一个数后再赋值,var a = 10; a += 5 // 15
  • *=、/=、%=: 乘、除、取模后再赋值,var a = 2; a *= 5 // 10

6. 双位运算符~~

  • 可以使用双位操作符来替代正数的Math.floor(), 替代负数的Math.ceil(),
  • 双位运算符的优势在于它执行相同的操作运算符速度更快
~~4.5                // 4
Math.floor(4.5)      // 4
Math.ceil(4.5)       // 5
 
~~-4.5               // -4
Math.floor(-4.5)     // -5
Math.ceil(-4.5)      // -4

7. 运算符的优先级

一元运算符里面的逻辑非优先级很高,逻辑与比逻辑或优先级高

  • 优先级1,小括号, ()
  • 优先级2,一元运算符,++ -- !
  • 优先级3,算数运算符,先 * / % 后 + -
  • 优先级4,关系运算符,> >= < <=
  • 优先级5,相等运算符,== != === !==
  • 优先级6,逻辑运算符,先&&后||
  • 优先级7,赋值运算符,= += -= *= /= %=
  • 优先级8,逗号运算符,,