javascript中的操作符可用于表达式中,将小的表达式连接成大的表达式。本文对常见操作符的一些规则做简要的总结。
算术操作符
++ 和 —
单目,++和--可用于数值的自加一和自减一。操作数会被转换为number,然后加一或减一,再赋值给操作数标识符。
整体表达式的值,取决于操作符合操作数的前后位置。如
let a = 1;
a++ // => 1,此时a === 2
--a // => 1,此时a === 1
复制代码
加号(+)
+用作单目运算符时,可将其后的操作数转换为数值。如:
+ 1 // => 1
+ "1" // => 1
> + {} // => NaN
复制代码
用作双目运算符时可用于数值的加减和字符串的拼接。
当2个操作数都为string或者number时规则最简单,如下
1 + 1 // => 2
"a" + "b" // => "ab"
复制代码
其他情况下,操作符的行为如下:
- 当操作数为对象时,会先将该对象转换为原始值。转换规则大致如下:对于Date对象,先调用
toString(),得到的结果为原始值时转换结束,否则调用valueOf(),如果该方法返回原始值直接使用,否则会抛出类型错误。对于其他内置Js类型,也是这样的转换,不过是先尝试valueOf(),后尝试toString()。 - 之后,如果有
string类型的操作数,则进行字符串的拼接,会将另一个操作数先转换为string类型,然后进行字符串的拼接。 - 否则,两个操作数会统一转化为
number类型,进行数值的加法运算。
示例如下:
1 + "2" // => "12"
1 + {} // => "1[object object]"
1 + [0] // => "10"
1 + null // => 1
1 + undefined // => NaN
true + true // => 2
复制代码
负号(-)
单目时将其后操作符转换为数值,然后改变符号。
- 1 // => -1
- "-1" // => 1
- {} // => NaN
复制代码
双目时,将两个操作数转换为number,然后进行减法运算。
乘除运算(* / % **)
将两个操作数转换为number,然后进行乘法、除法、取余或幂运算。
js中的数字都为浮点数。各种浮点数运算的结果不会被取整为整数。
其中,**与之前的Math.pow()功能相同,**有右结合特性,会优先计算**右边部分。如:
2 ** 3 ** 2 // => 2*(3*2)
复制代码
位运算符
位运算符会将操作数转化为数字,然后转换为2进制表示形式进行位运算。位运算符有 & 、|、^、~、<<、>>、>>>,分别会进行按位与、按位或
、按位异或、按位取非、左移、右移、零填充右移。
对一个值取非,相当于改变符号并减一。
对于一个值左移一位,相当于该值乘2。左移n位,相当于该值乘2^n。右移也是如此,会响应除2^n,并且会舍弃余数。例子如下:
0x1234 & 0x00FF // => 0x0034
0x1234 & 0x00FF // => 0x0FF0
~0x0F // => 0xFFFFFFF0
3 << 1 // => 6
7 >> 1 // => 3
-7 >> 1 // => -4
复制代码
关系操作符
=== 和 !==
=== 判断两个操作数是否严格相等并返回布尔值。不做类型转换,行为如下:
- 两个值类型不同,则不相等。
- 再判断值是否相等。
NaN属于number,但和任何值都不相等,包括自身(所以可用x !== x判断x是否为NaN)。+0和-0相等。- 对于
string,需要判断长度和相同位置对应的底层字符编码是否相等。 - 对于对象引用,只有引用同一值才相等。属性是否相同不作为判断依据。
!==和值和===相反。
== 和 !=
== 是基于类型转换的相等判断,如果两操作数类型不同,会尝试做类型转换,然后比较。
两数类型不同时,规则如下:
- 如果两值为
null和undefined,则相等。 - 如果一个值为
number,另一值为string,则将string转换为number,再比较数值。 - 布尔值会转换为数值0或1。
- 如果一个值为对象,另一值为数值或字符串,则先将对象转换为原始值,再比较。
- 其他任何值的组合都不相等。
例:
null == undefined // => true
"1" == true // => true,true转换为数值1,"1"转换为数值1,相等
["0"] == 0 // => true,
复制代码
对于第三个例子,[“0”]为偏向字符串的对象,首先尝试调用自身的toString(),结果为”0″,为基本类型,对象到原始值的转换完毕。然后将”0″转换为数值0,与右边操作数比较。
比较操作符
比较操作符包含>、<、>=、<=。其中>=和<=表示“不大于”和“不小于”,和==、===没有依赖关系。
比较符最终只会进行number之间的比较和string之间的比较。对于number会比较数值的大小,对于string会从首字母开始比较各个字母的Unicode编码值大小。如:
"abc" > "ABC" // => true,大写字母的编码值小于小写字母
复制代码
不能直接比较时,有如下规则:
- 对象值会被转换为原始值。
- 当两值都为字符串时,比较Unicode编码。
- 其他情况下,将两值转化为
number,比较大小。NaN和任何值比较结果都为false。
in操作符
in用于判断右侧对象中是否有左侧字符串属性。左侧操作数为字符串、Symbol或可以转化为字符串的值,右侧必须为对象。返回布尔值。
示例:
let obj = {a: 1};
"a" in obj // => true
"b" in obj // => false
"toString" in obj // => true,继承的方法
let arr = ["a", "b"]
"0" in arr // => true
1 in arr // => true,1会转换为"1"
3 in arr // => false
复制代码
instanceof
instanceof期待左侧操作数为对象,右侧操作数为对象类型,然后判断对象是否为该类型的实例,返回布尔值。
如:
let arr = [];
arr instanceof Array // => true
arr instanceof Object // => true
arr instanceof Date // => false
复制代码
instaceof依据原型链进行判断,对于obj instaceof f而言,会先取得f.prototype的值,然后判断obj.__proto__是否为f.prototype、查找到则返回true,否则会继续沿着原型链(obj._proto__.__proto__)查找,直至原型链的终点null,返回false。所有对象都是Object的实例。
逻辑操作符
逻辑与(&&)
&&常用于布尔值的运算,操作数都为true时返回true。如:
a === 1 && b === 2
复制代码
但&&并不要求操作数的类型。操作数为其他类型值时也有有趣的特性。JS中的值可被分为真值和假值。假值有:false、""、0、undefined、null。其他值为真值。
&&有短路的特性,当左操作数为真值时,返回的结果为右操作数。左操作数为假值时,返回结果为左操作数,并且不会对右操作数求值。如:
10 && 3 // => 3
1 && (console.log("r")) // 求值为右值,打印"r"。
0 && (console.log("r")) // => 0
复制代码
逻辑或(||)
类似于逻辑与,||也有短路的特性。当左操作数为真值时,返回结果为左操作数,不对右操作数求值。当左操作数为假值时,返回结果为右操作数。如:
10 || 3 // => 10
1 || (console.log("r")) // => 1
0 || (console.log("r")) // 求值为右值,打印"r"。
复制代码
逻辑非(!)
逻辑非没有短路特性,!会将操作数传唤为布尔值,然后取反,最终返回布尔值。一个常用的逻辑化简如下:
对一个逻辑表达式整体取反,相当于对操作数和操作符各自取反。
!(p && q) === (!p || q) // => true
复制代码
其他操作符
void
void返回值始终为undefined,但其之后的表达式仍会正常执行。可以用于不使用花括号的箭头函数。如:
let a = 1;
const a_pp = () => void(a++);
a_pp(); // => undefined
a; // => 2
复制代码
条件操作符(?:)
条件操作符接收三个操作数,第一个操作数会被转换为布尔值。为真时,返回第二个操作数;否则返回第三个操作数。如:
const bol = true
bol ? "1" : "0"; // => "1"
复制代码
先定义(??)
虽然它和条件操作符长得很像,但两者没有关系。是双目操作符,求值返回先定义的操作数。如果左操作数不为null或undefined,就返回左操作数,否则返回右操作数。如:
const apple = "apple"
apple ?? "new apple" // => "new apple"
复制代码
它也有类似于逻辑或(||)的短路性质,可用于判断值是否有效。区别在于||需要判断左操作数为真值还是假值。在逻辑或中""、0、false都是无效值。而在??中,它们为有效值。因此可以看做是对||的补充。如:
let str = "", num = 0;
str ?? str : "initial" // => "initial"
num ?? "exist" : "not exist" // => "exist"
复制代码
??和&&或||一起使用时,需要用圆括号表明先计算哪部分,不然会报错。
条件属性访问(?.)
javascript中,null和undefined两个值上不存在属性。因此,通过普通的属性访问(a.b或a[b])访问它们的属性会抛出TypeError。可以使用条件属性访问的方式(a?.b或a?[b])避免这种错误。如:
let a;
a?.b // => undefined
复制代码
对于a?.b,如果a为null或undefined,则该表达式值就为undefined,不会继续访问a.b这个属性;如果a不为null或undefined就会继续访问a.b。像a.b一样,它也可以链式访问。如:
let a = {b: null};
a?.b?.c?.d // => undefined
复制代码
同理,a?[b]也是同样的用法,当a为null或undefined时,不会访问a[b]。自然而然的,b所代指的表达式也不会执行求值。
条件调用(?())
类似于条件属性访问,条件调用符号为?(),可解决a()中a为null或undefined抛出的TypeError。如:
let a;
a?.comp() // => undefined,
复制代码
a为undefined,表达式值直接确定为undefined,不会真正的执行a.comp()。函数调用中左括号左操作数也必须为函数,因此,如例子中的a为函数之外的其他有意义变量,也会抛出TypeError。
?()也适用于方法调用,方法调用又包含了属性访问,因此,需要区分条件属性访问和条件方法调用。如:
o.m(); // 常规属性访问,常规方法调用
o?.m(); // 条件属性访问,常规方法调用
o.m?(); // 常规属性访问,条件方法调用
o?.m?(); // 条件属性访问,条件方法调用
复制代码
因此,第一个式中,o须为对象,且o.m为函数。第二个式中,o可为null或undefined;o为其他值时,o.m须为函数。第三个式中,o须为null和undefined之外的的值即可。第四个式中,o可为null或undefined;o为其他值时,o.m须为null或undefined或函数。




















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)