JS操作符

算术、位、关系、相等操作符

一元操作符

++、–、+、-

1
2
const f=1.1
f-- // 0.000000000000009 浮点舍入错误

位操作符

按内存中表示数值的位来操作数值。JS中的所有数值都以IEE754 64位格式存储,但位操作符并不直接操作64位的值。而是先将64位的值转换成32位的整数,然后执行操作,最后再将结果转换为64位。

在这个转换过程中,也会导致一个严重的负效应。对特殊的NaN和Infinity应用位操作时,这两个值会当做0来处理

有符号的整数,32位中前31位用于表示整数的值,第32位用于表示数值的符号(符号位)

  • 正数以纯二进制格式存储
  • 负数是以二进制补码存储(原码-反码-补码)
  1. 按位非NOT (波浪线~)

    本质是操作数的负值-1

  2. 按位与AND(和好符号&)
  3. 按位或OR (竖线符号|)
  4. 按位异或XOR (插入符号^):不同为1,相同为0
  5. 左移(<<):将数值的所有为向左移动指定的位数
1
2
3
const value= 2  // 等于二进制的10
const newValue= value << 5
// 等于二进制的10 00000 ,十进制的64

向左移位后,原数值的右侧多出了5个空位,左移操作会以0来填充这些空位。左移操作不会影响操作数的符号位。

  1. 有符号的右移(》》):将数值向右移动,但保留符号位。有符号的右移与左移恰好相反
1
2
const newValue= 64  //二进制的10 00000
const value= newValue >> 5 //二进制的10,即十进制的2

有符号的右移在移动过程中也会出现空位,不过这次的空位出现在原数值的左侧、符号位的右侧。此时会用符号位的值来填充所有空位。

  1. 无符号右移(>>>):对正数来说无符号的右移和有符号的右移相同。但对于负数,无符号右移会将负数的二进制当成正数的二进制码。负数以其绝对值的二进制的补码形式表示,就会导致无符号右移的结果非常大
1
2
3
const oldValue= -64 //二进制的 26个1 000000
const value= oldValue >>> 5
// 等于十进制的134217726

布尔操作符

  • 逻辑非会直接发生转换。
  • 逻辑与和逻辑或可以应用于任何类型的操作数,在有一个操作数不是布尔值的情况下,逻辑与和逻辑非不一定返回布尔值。
  1. 逻辑非NOT(!)

    逻辑非操作符首先会将他的操作数转换为一个布尔值,然后再对其取反

  2. 逻辑与AND(&&)

    短路操作,如果第一个操作数是false,无论第二个惭怍书是什么值,结果都是false

第一个操作数如果转布尔值为false时,则返回第一个操作数(null、NaN、undefined、’’、0、-0)

  1. 逻辑或OR

    短路操作,如果第一个操作数是true,无论第二个惭怍书是什么值,结果都是true

第一个操作数如果转布尔值为false时,则返回第而个操作数,如果两个操作数转而不都为false,则返回该操作数(null、NaN、undefined、’’、0、-0)

可以利用逻辑或来避免为变量赋null/undefined值

1
const myObject= preferedObject || backupObject

乘性操作符

在操作数不为数值的时候会执行自动的类型转换Number()

  1. 乘法*
  • 有一个操作数是NaN,则返回NaN
  • Infinity * 0 —— NaN
  • Infinity * Infinity —— Infinity
  • Infinity 与非0数值相乘,结果是Infinity或-Infinity,取决于有符号操作数的符号
  • 如果有一个操作数不是数值,则在后台调用Number()将其转换为数值,然后再用上面的方法
  1. 除法/
  • 有一个操作数是NaN,则返回NaN
  • Infinity / Infinity —— NaN
  • 0 / 0 —— NaN
  • 如果非0的有限数被0除,则结果是Infinity/-Infinity,取决于有符号操作数的符号
  • 如果是Infinity被任何非0数值除,则结果是Infinity/-Infinity,取决于有符号操作数的符号
  • 如果有一个操作数不是数值,则在后台调用Number()

如果结果超过了JS数值的范围,则返回Infinity或-Infinity

  1. 求模(余数%)
  • Infinity/ 有限大的数值——NaN
  • Infinity/ Infinity—— NaN
  • 有限大的数值/ 0——NaN
  • 有限大的数值/ 无穷大的数值——结果是被除数
  • x/0 —— 0
  • 有一个数不是操作数时,会先调用Number()

加性操作符

  1. 加法+
  • 一个操作数是NaN,则返回NaN
  • Infinity+Infinity——Infinity
  • -Infinity+(-Infinity)—— -Infinity
  • Infinity + (-Infinity)—— NaN
  • (+0) + (+0) —— +0
  • (-0) + (-0) —— -0
  • (+0) + (-0) —— +0
  • 两个操作数都是字符串,则拼接
  • 一个操作数是字符串,则将另一个操作数转换为字符串,然后再拼接
  • 如果有一个操作数是对象、数值、布尔,则调用他们的toString得到相应的字符串,然后再按照上面的规则
  1. 减法-
  • 一个操作数是NaN,则返回NaN
  • Infinity-Infinity——NaN
  • -Infinity-(-Infinity)—— NaN
  • Infinity - (-Infinity)—— Infinity
  • -Infinity - (Infinity)—— -Infinity
  • (+0) - (+0) —— +0
  • (-0) - (+0) —— -0
  • (-0) - (-0) —— +0
  • 如果有一个操作数是字符串、布尔、null、undefined,先调用Number(),若转换后为NaN,则结果为NaN,否则按照上面的规则
  • 如果有一个操作数是对象,则调用对象的ValueOf(),如果得到的是NaN,则结果为NaN。如果对象没有valueOf方法,则调用其toString()方法,并转换为数值

关系操作符

<、>、<=、>=、都返回一个布尔值

当关系操作符使用了非数值时,也要进行数据类型的转换

  • 两个操作数都是数值,进行数值的比较
  • 两个操作数都是字符串,比较两个字符串对应字符的字符编码值
  • 一个操作数是数值,则将另一个操作数转换为数值进行比较
  • 如果一个操作数是对象。调用对象的valueOf(),得到的结果按照上面的规则比较。如果对象没有valueOf方法,则调用toString()
  • 如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较
  • 任何操作数与NaN比较时,都是false(无论做哪种比较)

字符串比较对应字符的字符编码,大写字母的字符编码全部<小写字母的字符编码。如果要按照字母表的顺序比较字符串的大小,可以先把两个操作数转换为相同的大/小写格式,然后再比较。

1
2
3
4
5
6
'23' < '3' // true
'23' < 3 // false
'a' < 3 // false 'a'被转为了NaN

NaN > 2 // false
NaN <= 2 // false

相等操作符

1. 相等== 和不相等 !=

先转换再比较(强制转换)

  • 如果有一个操作数是布尔时,则在比较相等性之前将其转换为数值,false-0、true-1
  • 如果有一个操作数是字符串,另一个操作数是数值,先将字符串转换为数值
  • 如果一个操作数是对象,另一个不是,则调用对象的valueOf,用得到的基本类型值按照上面的方法判断
  • null和undefined相等
  • 比较相等性之前,不能将null、undefined转换为其他任何值
  • 有一个操作数是NaN,则相等返回false,不相等返回true(NaN和自身也不相等)
  • 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true。否则false

2. 全等=== 和不全等 !==

仅比较而不转换

逗号操作符

可用于声明多个变量,还可以用于赋值。在用于赋值时,逗号操作符总会返回表达式的最后一项

1
2
3
var num1=1, num2=2,num3=3

var num=(5,1,3,0) //0

在JS中switch中的case可以是常量、变量、表达式。switch语句在比较值的时候用的是全等操作符,因此不会发生类型转换。

1
2
3
4
5
switch(){
case value:
break;
default:
}

注意没有break时,就会执行完当前的case后,继续执行下一个。最后defalt用于在表达式不匹配前面任何一种case情况的时候。

1
'a' + + 'b' // -> "aNaN"