Javascript操作符运算合集
在javascript的语法中,不同类型通过操作符运算后求最终值这样的运算,在面试过程中会经常碰到,因此,今天我们就来一起探讨一下对应的规则。
四则运算符
+ 加法
加法有两种运算法则,分别为数字加法和字符串连接。运算时,它首先将两个操作数强制转换为基本类型后再计算。我们来一一举例:
-
若有一方是
字符串,则另一方会被转换成字符串,最后再连接起来形成新的字符串。const str = 'chuyuxuan' const num = 1 console.log(str + num) // chuyuxuan1 typeof (str + num) // 'string' -
若双方都是
BigInt,则执行BigInt加法。如果一方是 BigInt 而**另一方[1]**不是,会抛出 TypeError。// 双方都是 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。const 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转换为NaNnull转换为0true转换成1,false转换成0空字符串转换为0字符串转换为NaN(加法法则中则会都转成字符串)BigInt抛出TypeErrorSymbol抛出TypeError
注意,在BigInt中,使用Number(12n) 会得到 12 ,在ECMAScript是被允许的,但是这样会导致BigInt类 型的数据丢失精度。但是,如果利用BigInt 与 Number()实例进行混合运算则会报错,因为两者的基本类型不一致。详情可以见MDN对BigInt的描述。
- 减法
减法首先会把两边转换为数值,并根据两个操作数的类型执行数字减法,如果类型不匹配,则抛出 TypeError。与加法不一样,字符串也会优先转换成数值了,而不是先调用toString()进行转换。让我们来具体看下例子:
-
若双方
都是数值,则执行数值减法。const num1 = 100 const num2 = 50 console.log(num1 - num2) // 50 -
若双方都是
BigInt,则执行BigInt减法。如果一方是BigInt而**另一方[3]**不是,会抛出 TypeError。const 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。// 一方是 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相乘const myIn = Infinity const mystr = 'chuyuxuan' console.log( myIn * mystr ) // NaN console.log( myIn* myIn) // Infinity 与数值相乘都为无穷非数值基本类型相乘const myNull = null const mystr = '' const myUn = undefined console.log(myNull * mystr) // 0 console.log(myNull * myUn) // NaN
/ 除法
会先把两边转换为数值基本类型再进行除法运算,除法中,如果除数(符号右边)是 数值0,则会为 Infinity。有NaN 则为NaN
console.log(12 / 2);
// Expected output: 6
console.log(3 / Infinity );
// Expected output: 0 , 因为对于无穷来说,任何都趋近于0
console.log(Infinity / Infinity );
// Expected output: NaN 没有意义,不是一个数
console.log(12 / 'ewe');
// Expected output: NaN
console.log(Infinity / 0);
// Expected output: Infinity
逻辑运算符
==相等(松散相等)
松散相等运算符(==)检查其两个操作数是否相等,返回一个布尔值结果。它会比较不同类型的操作数,并尝试强制类型转换。
1.如果操作数具有相同的基本类型
-
Object:仅当两个操作数引用同一个对象时返回
true。const obj1 = {name:'chuyuxuan'} const obj2 = obj1 console.log(obj1 == obj2) // true const obj3 = {name:'chuyuxuan'} console.log(obj1 == obj3) // false -
String:只有当两个操作数具有相同的字符且顺序相同时才返回
true。const str1 = "chuyuxuan" const str2 = "chuyuxuan0v0" console.log(str1 == str2) // false console.log(str1 == str1) // true -
Number:如果两个操作数的值相同,则返回
true。+0、0和-0被视为相同的值。如果任何一个操作数是NaN,返回false;所以,NaN永远不等于NaN。console.log(18 == 18) // true console.log( -0 == +0) // true console.log(Infinity == Infinity) // true console.log(NaN == NaN) // false console.log( Number('chuyuxuan') == 18) //false -
Boolean:仅当操作数都为
true或都为false时返回true,否则返回false。console.log(true == true) // true console.log( false == false) // true console.log(false == true) // false -
BigInt:仅当两个操作数值相同时返回
true。console.log(18n == 18n) // true console.log(18n == 19n) // false -
Symbol:仅当两个操作数引用相同的符号时返回
true。const sy = Symbol('chuyuxuan') const mb = sy console.log(sy == mb) // true const ol = Symbol('chuyuxuan0v0') console.log(sy == ol) // false -
Null :两个操作数互为 null 时返回
true。console.log(null == null) // true -
Undefined:两个操作数互为 undefined 时返回
true。console.log(undefined == undefined) // true
2.如果操作数基本类型不同
2.1 如果其中一个操作数为 null 或 undefined,另一个操作数为 null 或 undefined 以返回 true。否则返回 false。
null == null // true
null == undefined // true
null == 1 // false
null == Symbol(1) // false
null == '' // false
null == true // false
null == 18n // false
null == [] // false
undefined == null // true
undefined == undefined // true
undefined == 1 // false
undefined == Symbol(1) // false
undefined == '' // false
undefined == true // false
undefined == 18n // false
undefined == [] // false
2.2 如果其中一个操作数是 Symbol 而另一个不是,返回 false。
Symbol('chuyuxuan') == null // false
Symbol('chuyuxuan') == 18n // false
Symbol('chuyuxuan') == 1 // false
Symbol('chuyuxuan') == 'chuyuxuan' // false
Symbol('chuyuxuan') == true // false
Symbol('chuyuxuan') == [] // false
Symbol('chuyuxuan') == undefined // false
2.3 如果其中一个操作数是布尔型而另一个是其他类型,则将布尔型转换为数值:true 转换为 1,false 转换为 0。然后再次松散地比较两个操作数(即一个操作数是数值,另一个不是的规则进行比较)。
console.log(true == 1 ) // true
2.4 如果一个操作数是字符串而另一个是数值。则会把字符串转换为数值,如果转换失败,则为 NaN,NaN 则会导致 false。
console.log("chuyuxuan" == 18 ) // false
console.log("5" == 5) // true
2.5 如果一个操作数是BigInt而另一个是数值。则会把BigInt通过Number转换为数值,如果数值为 ±∞ 或 NaN,则为false。
console.log( 18n == 18 ) // true
console.log( 18n == Infinity ) // false
3.如果操作数有引用类型
如果一个操作数是对象,另一个是基本类型,则会把对象的转成基本类型。
-
对象会首先调用内置的
Symbol.toPrimitive方法转(详情见MDN),若没有该方法,则往下。 -
对象再通过
valueOf()方法尝试转换,如果返回依然不是基本类型,则往下。 -
对象会继续调用
toString(),最后再执行基本类型比较。(从2.1开始,操作数具有相同的类型,接着往下,直至比较出结果跳出循环)。
const myNumberObj = new Number(18)
console.log(myNumberObj == 18) // true
const myStr = '[object Object]'
const myStringObj = {name:'chuyuxuan',age:18}
console.log(myStringObj == myStr) // true
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
所以,我们对以上进行逻辑非,那么就能够得到其正确的值。
{% note waring flat %} 逻辑非的优先级高于四则运算。 {% endnote %}