【JS全解】JS运算符

177 阅读4分钟

算数运算符

number 运算

  • 加减乘除:+、-、*、/
  • 余数:x%7
    • JS中,负数的余数是其绝对值的余数加负号。
    • -1%7的结果是-1
    • -9%7的结果是-2
  • 指数:x**3
  • 自增自减:x++++xx----x
    • x在前,x++表达式的值就是x;x在后,表达式++x的值就是x+1。
    • 尽量使用a+=1代替a++/a--
  • 求值运算符:+x
  • 负数运算符:-x
  • 自增自减助记
    • 每个运算符本质都是函数,只不过大多数运算符不会对参数本身做出操作。
    • 与其他运算符不同,自增自减是对参数本身进行操作的。
    • 可以把x++++x视为两个操作相同,但返回值不同的函数。
    • x++,函数内部的操作是x+=1,返回值是x-1。
    • ++x,函数内部的操作是x+=1,返回值是x。

string运算

  • 连接运算'123'+'456'
  • 字符串只支持+号运算,不支持其他运算符。
  • JS中,'2'+1,会对数字进行隐式转换。
  • JS中,'2'-1,会对字符串进行隐式转换。

比较运算符

  • >:左边是否大于右边。
  • <:左边是否小于右边。
  • >=:左边是否大于或等于右边。
  • <=:左边是否小于或等于右边。
  • ==:模糊相等,检验左右两边是否相等 ,会发生类型转换。
  • ===:全等,左右两边是否类型和值都相等。
  • !==:左右两边是否不全等。
  • 比较的结果为boolean类型,即只会得到true或false。
  • 注意
    • 永远不要使用==,用===代替。
    • ==的问题在于,它会自动类型转换,详细搜索“JS三位一体”。
    • {} !== {} // true[] !== [] // true对象和数组存的都是地址。
    • NaN !== NaN // true,并且NaN不和任何元素相等。

布尔运算符

  • 布尔运算符用来解决多重条件判断。
  • | 符号 | 名称 | 特点 | |:---:|:---:|:---:| | && | 逻辑与 | 符号两边都为true,结果才为true | | || | 逻辑或 | 符号两边有一个true,结果就为true | | ! | 逻辑非 | true变false,false变true |

短路逻辑

  • 符号短路条件
    &&左边为false就短路
    ||左边为true就短路
  • 运算结果:无论&&还是||,运算结果都是最后被执行的表达式值。
    1. 如果发生短路,则左边的式子结果就是整个逻辑运算的结果。
    2. 如果没有发生短路,则右边式子的结果就是整个逻辑运算的结果。
  • 实际运用
    • 防御性编程,比如防止console.log不存在的报错:console && console.log && console.log('hi')
    • 为a设置一个保底值100:a = a || 100。现不推荐,已经有更好的语法了。

二进制运算符

  • 或、与、否,只对二进制数有效。
    • |:两个位都为0,则结果为0,否则为1。
      • 例:(0b1111|0b1010).toString(2)//"1111"
    • &:两个位都为1,则结果为1,否则为0。
      • 例:(0b1111&0b1010).toString(2)//"1010"
    • ~:把0变成1,1变成0。
      • 例:(0b1111~0b1010).toString(2)//"-10000"
      • 为什么结果会变成负数?因为要补码。
  • 异或
    • ^:两个位相同,则结果为0,否则为1。
      • 例:(0b1111^0b1010).toString(2)//"101"
  • 左移右移
    • <<:整体向左移。
      • 例:0b0010 << 2 // 1000
    • >>:整体向右移,如果有多余的“1”,则会被抹去。
      • 例:0b0011 >> 1 // 1
  • 头部补零的右移运算符
    • >>>:在正数的情况下,>>和>>>几乎没有区别。

位运算符在JS中的妙用

使用与运算符判断奇偶

偶数 & 1 = 0
奇数 & 1 = 1
  • &运算是在两个位都是1的情况下才会返回1。
  • 二进制下,偶数的最后一位都为0,奇数的最后以为都为1。
  • 让一个数同1做&运算可以知道它的最后一位是0还是1。

使用~, >>, <<, >>>, |来取整

console.log(~~ 6.83)    // 6
console.log(6.83 >> 0)  // 6
console.log(6.83 << 0)  // 6
console.log(6.83 | 0)   // 6
console.log(6.83 >>> 0) // 6
  • 位运算不支持小数,会自动把小数抹去。
  • 对于console.log(6.83 | 0),是因为任何数字和0做或运算,结果都是它本身。

使用^来交换a、b的值

var a = 5
var b = 8
a ^= b
b ^= a
a ^= b
console.log(a) // 8
console.log(b) // 5
  • 类似于负负得正的原理。

点运算符

  • 语法:对象.属性名 = 属性值
  • 作用:读取对象的属性值。
  • JS有特殊逻辑,点前面不是对象,就把它封装成对象。
    • number会变成Number对象
    • string会变成String对象
    • bool会变成Boolean对象
  • 因此非对象也可以有属性,例:'a-b-c'.split('-')。在这一过程中有三个步骤:
    1. 把'a-b-c'封装成String对象。
    2. 调用Spring.split()。
    3. 删除String对象。

void运算符

  • 语法:void 表达式或语句
  • 作用:求表达式的值或执行语句。void的值总是为undefined。

逗号运算符

  • 语法:表达式1, 表达式2, ..., 表达式n
  • 作用:将表达式n的值作为函数的最终值。
  • 例:let a = (1,2,3,4,5) // a=5
  • 在不用return的情况下,执行多条语句:
    let f = (x) => (console.log('平方值为'), x*x) // 小括号不能省略
    

运算符优先级

  • | 优先级 | 运算符 | 顺序 | |:---:|:---:|:---:| | 1 | 小括号 | () | | 2 | 一元运算符 | ++ -- ! | | 3 | 算数运算符 | /%,后+-* | | 4 | 关系运算符 | > >= < <= | | 5 | 相等运算符 | == != === !== | | 6 | 逻辑运算符 | 先&&,后|| | | 7 | 赋值运算符 | = | | 8 | 逗号运算符 | , |
  • 一元运算符里面的逻辑非优先级很高。
  • &&与比||优先级高。
  • 在实际操作中,直接用优先级最高的小括号来把希望优先执行的代码括起来就行。
  • 运算符优先级 MDN
  • 相同运算符的先后运算顺序
    • 从左往右:a + b = c
    • 从右往左:a = b = c = d

拓展

function fn(n = 0)

  • 为了解决a = a || 100中,空字符串和0被识别为false的问题,JS发明了新的语法:
    function fn(n=0){
    	return n+1
    }
    
  • 在这种语法下,只有null和undefined才会被识别为false。

[a,b]=[b,a]

  • JS新版语法中可以通过[a,b]=[b,a]来交换两个变量的值:
    var a = 1, b = 2
    [a, b] = [b, a]
    a // 2
    

面试官の质询:你为什么不记运算符优先级呢?

  • JS运算符优先级有20多个等级,我觉得大部分人都不会全部记住,哪怕是我未来的同事。在实际工作中,为了防止同事看不懂我的代码,我可以、也更应该直接用优先级最高的小括号把希望优先执行的代码包裹起来就好。

方方の敦敦教诲

  • 其一:少用/不要用==、++、Number对象、Boolean对象、String对象。