JavaScript高级程序设计-4-基本概念2-操作符
接上文JavaScript高级程序设计-3-基本概念1-数据类型。
操作符
ECMA-262定义了一组用于操作数据值的操作符,包括算术操作符(加号/减号)、位操作符、关系操作符和相等操作符。ES中的操作符的特殊之处在于,它们能适用于不同的值,如字符串、数字值、布尔值、甚至对象,不过当操作数是对象时,相应的操作符通常需要调用对象的valueOf或toString方法,以便取得可以操作的值。
一元操作符
只能操作一个值的操作符叫一元操作符
递增/减操作符
递增/减操作符借鉴于C语言,而且也有两个版本,前置型和后置型,两者区别是:执行前置操作时,变量的值都是在语句被求值以前改变的,即先执行一元操作符,在执行其他计算操作。而后置操作则相反。1
2
3
4
5
6
7
8
9
10
11// 前置
var num1 = 2;
var num2 = 20;
var num3 = --num1 + num2; // 21
var num4 = num1 + num2; // 21
// 后置
var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2; // 22
var num4 = num1 + num2; // 21
它们不仅可以用于整数,还可以用于字符串、布尔值、浮点数和对象,规则如下:
- 当用于一个包含有效数字字符的字符串时,现将其转换为数字值,在执行自增/减1操作,字符串变量变为数值变量
- 当用于一个不包含有效数字字符的字符串时,将变量的值设置为NaN,字符串变量变为数值变量
- 当用于布尔值false时,先将其转换为0,然后执行自增/减1操作,布尔值变量变为数值变量
- 当用于布尔值true时,先将其转换为1,然后执行自增/减1操作,布尔值变量变为数值变量
- 当用于浮点数值时,执行自增/减1操作
- 当用于对象时,先调用对象的valueOf方法以取得一个可供操作的值,然后对该值应用上述规则,若结果为NaN,则调用对象的toString方法,然后再应用上述规则,对象变量变为数值变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14var s1 = "2",
s2 = "z",
b = false,
f = 1.1,
o = {
valueOf: function(){
return -1;
}
};
s1++; // 3
s2++; // NaN
b++; // 1
f--; // 0.100000000000001 浮点数有舍入误差
o--; // -2
一元加/减操作符
这两个ES操作符的作业与数学上的完全一致,一元加(+
)放在数值前不会产生任何影响:1
2var num = 22;
num = +num; // 22
但,若对非数值应用一元加操作符时,则该操作符会像Number()转型函数一样对这个值执行转换,即,布尔值false和true将被转换为0和1,字符串会按照字符串规则进行解析,而对象先调用valueOf或toString,再转换其值。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var s1 = "01",
s2 = "1.1",
s3 = "z",
b = false,
f = 1.1,
o = {
valueOf: function(){
return -1;
}
};
s1 = +s1; // 1
s2 = +s2; // 1.1
s3 = +s3; // NaN
b = +b; // 0
f = +f; // 1.1
o = +o; // -1
一元减则是将数值转换为负数,当应用于数值时,直接返回负数,若应用于非数值时,则先按照一元加的规则将其转换为数值,然后再转换为负数。
位操作符
位操作符用于一个最基本的层次上,即按内存中表示数值的位来操作数值。ES中所有数值都以64位IEEE75格式存储,但位操作符不能直接操作64位的值,而是将64位的值转换为32位的整数,然后执行操作,最后再将结果转换回64位。对于开发者而言,整个过程是透明的,就像只存在32位的整数一样。
对于有符号的整数,32位中的前31位用于表示整数的值,第32位用于表示数值的符号,叫做符号位,0表示正,1表示负,符号位的值决定了其他位数值的格式。
正数以纯二进制格式存储,31位中的每一位都表示2的幂,没有用到的位以0填充,计算时忽略,比如:0000010010简化为10010,表示数值18.
负数以二进制补码格式存储,求补码的步骤为:先求绝对值的二进制码,然后求其反码,最后加1即可。
而ES将上述的很多细节隐藏了,比如输出一个负数的二进制字符串时仅仅是在这个数的绝对值的二进制前加一个负号:1
2var num = -18;
num.toString(2); // "-10010"
注:默认情况下,ES中所有的整数都是有符号整数,不过,也有无符号整数,即第32位不表示符号,而无符号整数只能表示正数。
同时,由于ES将64位转换为32位再计算位操作,所以对NaN和Infinity两个值应用位操作时,这两个值将被当做0处理。
对非数值应用位操作符,会先使用Number()将值转换为一个数值,然后再应用位操作,得到的结果将是一个数值。
1.按位非(NOT)
按位非操作符用波浪线(~
)表示,按位非的结果就是返回数值的反码。1
2var num = 25; // 二进制 0..011001
var num2 = ~num1; // -26, 二进制 1..1100110
对25执行按位非操作,结果得到-26,按位非的本质:操作数的负值减1。同时由于是最底层支持操作,因此速度很快。
2.按位与(AND)
按位与操作符用and字符(&
)表示,需要两个操作数,将两个操作数的每一位对齐,然后只有对应位都是1时返回1,否则返回0。1
2
3
4var result = 25 & 3; // 1
// 25 = 0..0 0001 1001
// 3 = 0..0 0000 0011
//AND = 0..0 0000 0001
上例中,25和3的二进制对应只有1位同时为1,其他位都是0,所以最终结果为1
3.按位或(OR)
按位或操作符用竖线符号(|
)表示,需要两个操作数,将两个操作数的每一位对齐,然后只有对应位都是0时返回0,否则返回1。1
2
3
4var result = 25 | 3; // 27
// 25 = 0..0 0001 1001
// 3 = 0..0 0000 0011
// OR = 0..0 0001 1011
4.按位异或(XOR)
按位异或操作符由一个插入符号(^
)表示,需要两个操作数,将两个操作数的每一位对齐,然后只有对应位不同时返回1,否则返回0。1
2
3
4var result = 25 ^ 3; // 26
// 25 = 0..0 0001 1001
// 3 = 0..0 0000 0011
//XOR = 0..0 0001 1010
5.左移
左移操作符由两个小于号(<<
)表示,将操作数的所有位向左移动指定位数,以0填充右侧的空位。1
2var oldVal = 2; // 二进制 10
var newVal = oldVal << 5; // 二进制 1000000 ,十进制64
左移不会影响操作数的符号位,即,若将-2左移5位,则结果是-64,而不是64。
6.有符号右移
有符号右移操作符由两个大于号(>>
)表示,将操作数的所有位向右移动指定位数,但保留符号位,即与左移相反, 以符号位填充左侧的空位。1
2var oldVal = 64; // 二进制 1000000
var newVal = oldVal >> 5; // 二进制 10 ,十进制2
7.无符号右移
无符号右移操作符由三个大于号(>>>
)表示,以0填充左侧的空位,所以对正数来说,结果与有符号右移相同,但对负数来说,因为负数使用绝对值的二进制补码格式存储的,而结果就是解释为正数的时变得非常大。1
2var oldVal = -64; // 二进制 1..11000000
var newVal = oldVal >>> 5; // 等于十进制134217726
布尔操作符
布尔操作符有三个:逻辑非(NOT)、逻辑与(AND)、逻辑或(OR)。
逻辑非(NOT)操作符由叹号(!
)表示, 将一个值转换为与其对应的布尔值,然后求反。但连续使用两个非操作符结果与Boolean()转型函数相同。
逻辑与(AND)操作符由两个&号(&&
)表示,逻辑或(OR)由两个|号(||
)表示,都有短路运算的效果。
乘性操作符
乘性操作符有三个:乘,除,求模。与C语言类型,只不过,当操作数为非数值时将会自动执行类型转换,即先用Number()转型函数将其转换为数值,例如:空字符串转为0,true转为1,然后再计算。
加性操作符
加性操作符有2个:加和减。
对加来说,其实规则比较复杂,而且比较容易出错,总结下来:
- 当两个操作数都是数值时,则结果为常规结果。
- 若有一个操作数是字符串,则会被当做字符串的链接操作,另一个操作数将先转化为字符串,再连接
- 若有一个数值,结果是先将另一个操作数(非字符串非数值的变量)转换为数值,然后再计算。
对减也与加类似,但是原则是将非数值尽量转换为数值,然后进行计算。
关系操作符
关系操作符有: <
, >
, <=
, >=
,是比较两个值的大小。结果是一个布尔值,规则如下:
- 当操作数都为数值时,直接比较
- 当操作数都是字符串时,比较字符串对应的字符编码(ASCII码)
- 当一个是数值时,则将另一个转换为数值,再进行比较
- 当一个是布尔值时,将布尔值转换为数值,再进行比较
- 当操作数为对象时,则调用操作数的valueOf方法,若没有则调用toString方法,调用方法的结果再按上述规则比较。
相等操作符
确定两个变量是否相等子是一个非常重要的操作,在比较字符串、数值、布尔值时比较简单,但涉及对象时就比较复杂了,ES提供了两组操作符:相等/不相等(先转换再比较),全等/不全等(不转换直接比较)。
ES中的相等由==
表示,不相等由!=
表示,当数据类型不同时,先转换操作数,再进行比较,规则如下:
- 若一个操作数是布尔值,则先将其转换为数值
- 若一个操作数是字符串,另一个是数值,则先将字符串转换为数值
- 若一个是对象,另一个不是,则调用对象的valueOf方法,得到基本类型后再按照前面的规则比较
需要注意的是: - null和undefined是相等的,在比较相等性之前,不能将null和undefined转换为其他任何值
- 若有一个操作数是NaN,则相等操作符直接返回false,而不相等操作符返回true。
- 若两个操作数都是对象,则比较其是否是同一个对象,若是则返回true,否则返回false。(不进行深度比较)
推荐优先使用全等/不全等(不转换直接比较)。
条件操作符
条件操作符即三元操作符(? :
),与其他语言的规则无区别,先求取表达式的结果,再决定执行哪一个表达式。
赋值操作符
赋值操作符为=
,与其他语言的规则无区别,需要注意的就是复合赋值操作符(*=
,+=
,-=
等)的目的是简化赋值操作,并不会带来任何性能提升。
逗号操作符
逗号操作符用于在一条语句中执行多个操作,多用声明多个变量。需要注意的是,当赋值时,逗号操作符总会返回表达式的最后一项。1
var num = (4,5,6,.1,0); // 0