Javascript操作符运算合集
Javascript操作符运算合集
在javascript
的语法中,不同类型通过操作符运算后求最终值这样的运算,在面试过程中会经常碰到,因此,今天我们就来一起探讨一下对应的规则。
四则运算符
+
加法
加法有两种运算法则,分别为数字加法和字符串连接。运算时,它首先将两个操作数强制转换为基本类型
后再计算。我们来一一举例:
若有一方是
字符串
,则另一方会被转换成字符串
,最后再连接起来形成新的字符串
。1
2
3
4const str = 'chuyuxuan'
const num = 1
console.log(str + num) // chuyuxuan1
typeof (str + num) // 'string'若双方都是
BigInt
,则执行BigInt
加法。如果一方是 BigInt 而**另一方[1]**不是,会抛出 TypeError。1
2
3
4
5
6
7
8
9
10// 双方都是 BigInt
const bnum1 = 2024n
const bnum2 = 2025n
console.log(bnum1 + bnum2) // 4049n
typeof (bnum1 + bnum2) // 'bigint'
// 一方不是 BigInt
const bigNum = 2024n
const myBoolean = true
console.log(bigNum + myBoolean) // Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions[1]注意,如果有一方是**字符串**,则会执行上述
字符串
的规则除上述外,若双方都是其他基本类型,则都会被转换成 数字类型[2],再进行加法运算。如果有任一操作数是
NaN
,则返回NaN
。1
2
3
4
5
6
7const myNull = null
const myBoolean = false
const myUndefined= undefined
console.log(myNull + myBoolean) // 0
console.log(myNull + myUndefined) // NaN
// myNull 会转换成数字 0, myBoolean 会转换成数字 0 ,myUndefined 会转换成 NaN[2]调用 Number() 将其参数转换为数字进行混合计算时。部分参数转换结果如下,其他请参考MDN:
- Number 将按原样返回,包括正负号
Infinity
返回自身,包括正负号undefined
转换为NaN
null
转换为0
true
转换成1
,false
转换成0
空字符串
转换为0
字符串
转换为NaN
(加法法则中则会都转成字符串)BigInt
抛出TypeError
Symbol
抛出TypeError
注意,在BigInt
中,使用Number(12n) 会得到 12 ,在ECMAScript是被允许的,但是这样会导致BigInt类型的数据丢失精度。但是,如果利用BigInt 与 Number()实例进行混合运算则会报错,因为两者的基本类型不一致。详情可以见MDN对BigInt的描述。
-
减法
减法首先会把两边转换为数值,并根据两个操作数的类型执行数字减法,如果类型不匹配,则抛出 TypeError。与加法不一样,字符串也会优先转换成数值了,而不是先调用toString()进行转换。让我们来具体看下例子:
若双方
都是数值
,则执行数值减法。1
2
3const num1 = 100
const num2 = 50
console.log(num1 - num2) // 50若双方都是
BigInt
,则执行BigInt
减法。如果一方是BigInt
而**另一方[3]**不是,会抛出 TypeError。1
2
3
4
5const b1 = 100n
const b2 = 50n
const str = 'chuyuxuan'
console.log(b1 - b2) // 50n
console.log(b1 - str) // TypeError: Cannot mix BigInt and other types, use explicit conversions
[3] 除了BigInt的其他基本类型
若双方都是
非数值
,则会先用Number()转换成数值,再计算。Number转换规则见注解2。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 一方是 string,一方是 null
const str = 'chuyuxuan'
const myNull = null
console.log(myNum - myNull) // NaN
// string 会被转换成NaN ,NaN 除了 BitInt 基本类型外,相减(无论是减数还是被减数)都为NaN
// 一方是 Infinity,一方是 boolean
const myBoolean = false
const num = Infinity
console.log(myBoolean - num) // -Infinity
// myBoolean 会被转换为 0, 0 减去一个数值,取反。
// 一方是 Symbol ,一方是 undefined
const ms = Symbol('chuyuxuan')
const myUndefined = undefined
console.log(myUndefined - ms) // TypeError: Cannot convert a Symbol value to a number
// Symbol 不能和任何 Number 实例混合运算
*
乘法
乘法运算也一样,会先把两边转换为数值基本类型再进行乘积运算。不过需要注意一下Infinity 与 NaN:
Infinity
相乘1
2
3
4const myIn = Infinity
const mystr = 'chuyuxuan'
console.log( myIn * mystr ) // NaN
console.log( myIn* myIn) // Infinity 与数值相乘都为无穷非数值基本类型
相乘1
2
3
4
5const myNull = null
const mystr = ''
const myUn = undefined
console.log(myNull * mystr) // 0
console.log(myNull * myUn) // NaN
/
除法
会先把两边转换为数值基本类型再进行除法运算,除法中,如果除数(符号右边)是 数值0,则会为 Infinity。有NaN 则为NaN
1 | console.log(12 / 2); |
逻辑运算符
==
相等(松散相等)
松散相等运算符(==
)检查其两个操作数是否相等,返回一个布尔值结果。它会比较不同类型的操作数,并尝试强制类型转换。
1.如果操作数具有相同的基本类型
Object:仅当两个操作数引用同一个对象时返回
true
。1
2
3
4
5
6const obj1 = {name:'chuyuxuan'}
const obj2 = obj1
console.log(obj1 == obj2) // true
const obj3 = {name:'chuyuxuan'}
console.log(obj1 == obj3) // falseString:只有当两个操作数具有相同的字符且顺序相同时才返回
true
。1
2
3
4const str1 = "chuyuxuan"
const str2 = "chuyuxuan0v0"
console.log(str1 == str2) // false
console.log(str1 == str1) // trueNumber:如果两个操作数的值相同,则返回
true
。+0
、0
和-0
被视为相同的值。如果任何一个操作数是NaN
,返回false
;所以,NaN
永远不等于NaN
。1
2
3
4
5console.log(18 == 18) // true
console.log( -0 == +0) // true
console.log(Infinity == Infinity) // true
console.log(NaN == NaN) // false
console.log( Number('chuyuxuan') == 18) //falseBoolean:仅当操作数都为
true
或都为false
时返回true
,否则返回false
。1
2
3console.log(true == true) // true
console.log( false == false) // true
console.log(false == true) // falseBigInt:仅当两个操作数值相同时返回
true
。1
2console.log(18n == 18n) // true
console.log(18n == 19n) // falseSymbol:仅当两个操作数引用相同的符号时返回
true
。1
2
3
4
5
6const sy = Symbol('chuyuxuan')
const mb = sy
console.log(sy == mb) // true
const ol = Symbol('chuyuxuan0v0')
console.log(sy == ol) // falseNull :两个操作数互为 null 时返回
true
。1
console.log(null == null) // true
Undefined:两个操作数互为 undefined 时返回
true
。1
console.log(undefined == undefined) // true
2.如果操作数基本类型
不同
2.1 如果其中一个操作数为 null
或 undefined
,另一个操作数为 null
或 undefined
以返回 true
。否则返回 false
。
1 | null == null // true |
2.2 如果其中一个操作数是 Symbol
而另一个不是,返回 false
。
1 | Symbol('chuyuxuan') == null // false |
2.3 如果其中一个操作数是布尔型
而另一个是其他类型,则将布尔型
转换为数值
:true
转换为 1,false
转换为 0。然后再次松散地比较两个操作数(即一个操作数是数值
,另一个不是的规则进行比较)。
1 | console.log(true == 1 ) // true |
2.4 如果一个操作数是字符串
而另一个是数值
。则会把字符串
转换为数值
,如果转换失败,则为 NaN
,NaN
则会导致 false。
1 | console.log("chuyuxuan" == 18 ) // false |
2.5 如果一个操作数是BigInt
而另一个是数值
。则会把BigInt
通过Number
转换为数值
,如果数值为 ±∞
或 NaN
,则为false。
1 | console.log( 18n == 18 ) // true |
3.如果操作数有引用类型
如果一个操作数是对象
,另一个是基本类型
,则会把对象
的转成基本类型
。
对象会首先调用内置的
Symbol.toPrimitive
方法转(详情见MDN),若没有该方法,则往下。对象再通过
valueOf()
方法尝试转换,如果返回依然不是基本类型,则往下。对象会继续调用
toString()
,最后再执行基本类型比较。(从2.1开始,操作数具有相同的类型,接着往下,直至比较出结果跳出循环)。
1 | const myNumberObj = new Number(18) |
MDN 中对 valueOf()解释如下:
Object
实例的 valueOf()
方法将 this
值转换成对象。该方法旨在被派生对象重写,以实现自定义类型转换逻辑。
大白话就是 new对象给的初始值就是 valueOf的返回值,例如 let strObj = new String('chuyuxuan')
,则在 strObj 上this指向值为 ‘chuyuxuan’
在上述比较过程中,valueOf()
的返回值不是属于基本类型里面的,则会继续调用toString()
方法,转换成String
类型,进行比较。
!
逻辑非
如果其操作数可以转化为 true
,则返回 false
,否则返回 true
。虽然挺废话的,但也是如此,😂。
其实我们可以这样理解,!
就是对 操作数转成Boolean类型之后,进行取反。如何把一个类型转成Boolean类型?我们可以借用 Boolean()
构造函数。**Boolean()
** 构造函数可以创建 Boolean
对象或返回布尔类型的原始值。
在Boolean构造函数中,当起参数为一下基本类型:
没有值(或者省略)
0
-0
+0
0n
null
false
NaN
undefined
“” (空字符串)
Boolean()
构造函数 返回 false
若参数为
- 任何对象 (当然,这里也包括
[]
空数组) - 非空字符串
Boolean()
构造函数 返回 true
所以,我们对以上进行逻辑非,那么就能够得到其正确的值。
逻辑非的优先级高于四则运算。