
——跟我一起学 javaScript (6)
ECMAScript 操作符能够适应多种类型的值。
应用于对象时,相应的操作符会调用对象的 valueOf() 或 toString() 方法,以取得可以操作的值。
1 一元操作符
只能操作一个值
1.1 递增与递减操作符
分为前置和后置两种情况
前置递增或递减时,变量的值都是在语句被求值以前改变的,称为副效应:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>前置递增与递减的副效应</title>
</head>
<body>
<script type="text/
Javascript">
var age = 19;
var anotherAge = --age + 2;
console.log(age);//18
console.log(anotherAge);//20
</script>
</body>
</html>
由于前置递增和递减操作与执行语句的优先级相等,因此整个语句会从左到右被求值:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>前置递增与递减与执行语句的优先级相等</title>
</head>
<body>
<script type="text/javascript">
var num1 = 2;
var num2 = 20;
console.log(--num1 + num2);//21
console.log(num1 + num2);//21
</script>
</body>
</html>
后置型的递增和递减操作会在包含的语句被求值后才执行:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>后置递增与递减在包含它们的语句求值后才执行</title>
</head>
<body>
<script type="text/javascript">
var num1 = 2;
var num2 = 20;
console.log(num1-- + num2);//22
console.log(num1 + num2);//21
</script>
</body>
</html>
规则如下:
应用的对象 |
操作 |
包含有效数字字符 |
转换为数字值,再执行 |
不包含有效数字字符 |
NaN |
false |
转换为0,再执行 |
true |
转换为1,再执行 |
浮点数值 |
执行 |
对象 |
先调用对象的 valueOf() 方法取得值,然后应用上述规则;如果结果是 NaN,再调用 toString() 方法取得值,然后应用上述规则 |
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>后置递增与递减操作符规则</title>
</head>
<body>
<script type="text/javascript">
var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function () {
return -1;
}
};
s1++; //3
s2++;//NaN
b++;//1
f--;//0.10000000000000009(浮点舍入错误)
o--;//-2
</script>
</body>
</html>
1.2 一元加和减操作符
一元加操作符放在数值前面,对数值不会产生影响。
对非数值应用一元加操作符,会像调用 Number() 转型函数一样对这个值执行转换:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>不同数据类型应用一元操作符类型</title>
</head>
<body>
<script type="text/javascript">
var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var 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
</script>
</body>
</html>
一元减操作符用于表示负数。
对非数值应用一元减操作符时,也会遵循与一元加操作符相同的规则,最后再把数值转换为负数:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>一元减操作符应用于数值时,该值会变为负数</title>
</head>
<body>
<script type="text/javascript">
var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function () {
return -1;
}
};
s1 = -s1;//-1
s2 = -s2;//-1.1
s3 = -s3;//NaN
b = -b;//0(
Chrome 中会变为 -0)
f = -f;//-1.1
o = -o;//1
</script>
</body>
</html>
一元加和减操作符主要用于算术运算,也可用于数据类型的转换。
2 位操作符
位操作符会按内存中表示数值的位来操作数值。
ECMAScript 中所有的数值都是以 IEEE-754 64 位格式存储,但位操作符会先将 64 位的值转换为 32 位的整数,然后执行操作,最后再将结果转换为 64 位。这会导致严重的副效应,即对 NaN 和 Infinity 值应用位操作时,会被当做 0 来处理。
对于有符号整数,第 32 位表示数值的符号;0 表示正数,1 表示负数。
负数使用的格式是二进制补码。
计算二进制补码的步骤:
1. 求数值绝对值的二进制码
2. 求二进制反码
3. 将二进制反码加 1
ECMAScript 会隐藏上面的信息,以二进制字符串形式输出负数时,只会在这个负数绝对值的二进制码前加一个负号:
var num = -18;
alert(num.toString(2)); //"-10010"
默认情况下,ECMAScript 中所有整数都是有符号整数。
如果对非数值应用位操作符,会先自动使用 Number() 函数将该值转换为数值,再进行下一步操作。
2.1 按位非
由波浪线(~)表示,返回数值的反码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>按位非</title>
</head>
<body>
<script type="text/javascript">
var num1 = 25;
var num2 = ~num1;
console.log(num2);//-26
</script>
</body>
</html>
2.2 按位与
由 & 表示,对相同位置上的两个数执行 AND 操作,规则如下:
第一个数的位 |
第二个数的位 |
结果 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
即按位与操作中,只有两个数值对应的位都是 1 时,才返回 1。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>按位与</title>
</head>
<body>
<script type="text/javascript">
var result = 25 & 3;
console.log(result);//1
</script>
</body>
</html>
2.3 按位或
由 | 表示,规则如下:
第一个数的位 |
第二个数的位 |
结果 |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
0 |
0 |
即按位或操作中,只有两个数值对应的位都是 0 时,才返回 0。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>按位或</title>
</head>
<body>
<script type="text/javascript">
var result = 25 | 3;
console.log(result);//27
</script>
</body>
</html>
2.4 按位异或
由插入符号 ^ 表示,规则如下:
第一个数的位 |
第二个数的位 |
结果 |
1 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
0 |
0 |
只有两个数值对应的位只有一个 1 时,才返回 1。
2.5 左移
由两个小于号(<<)表示,会将数值中的所有位向左移动指定的位数。
左移后多出的空位会以 0 来填充。
左移不会影响操作数的符号位。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>左移</title>
</head>
<body>
<script type="text/javascript">
var oldValue = 2;
console.log(oldValue << 5);//64
</script>
</body>
</html>
2.6 有符号的右移
由两个大于号(>>)表示,会将数值中的除了符号位之外的所有位向右移动指定的位数:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>有符号右移</title>
</head>
<body>
<script type="text/javascript">
var oldValue = 64;
console.log(oldValue >> 5);//2
</script>
</body>
</html>
2.7 无符号右移
由三个大于号(>>>)表示,会将数值中的所有位向右移动指定的位数:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>无符号右移</title>
</head>
<body>
<script type="text/javascript">
var oldValue = 64;
console.log(oldValue >>> 5);//2
</script>
</body>
</html>
负数是以其绝对值额二进制补码形式表示,所以对负数执行无符号右移后,结果会变得非常大。
3 布尔操作符
3.1 逻辑非
由 ! 表示,可以应用于任何 ECMAScript 类型。规则如下:
操作数 |
结果 |
对象 |
false |
空字符串 |
true |
非空字符串 |
false |
0 |
true |
非 0 数值(包括 Infinity) |
false |
null |
true |
NaN |
true |
undefined |
true |
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>逻辑非</title>
</head>
<body>
<script type="text/javascript">
console.log(!false);//true
console.log(!"blue");//false
console.log(!0);//true
console.log(!NaN);//true
console.log(!"");//true
console.log(!12345);//false
</script>
</body>
</html>
同时使用两个逻辑非操作符,实际上就会模拟出 Boolean() 函数的行为:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>两个逻辑非可以模拟出一个 Boolean 函数</title>
</head>
<body>
<script type="text/javascript">
console.log(!!"blue");//true
console.log(!!0);//false
console.log(!!NaN);//false
console.log(!!"");//false
console.log(!!12345);//true
</script>
</body>
</html>
3.2 逻辑与
由 && 表示,规则如下:
第一个操作数 |
第二个操作数 |
结果 |
true |
true |
true |
true |
false |
false |
false |
true |
false |
false |
false |
false |
可以应用于任何类型的操作数。
如果有一个操作数不是布尔值,就不一定返回布尔值,具体规则:
操作数类型 |
结果 |
第一个操作数是对象 |
返回第二个操作数 |
第二个操作数是对象 |
只有第一个操作数求值结果为 true,才会返回该对象 |
两个操作数都是对象 |
返回第二个操作数 |
有一个操作数是 null |
null |
有一个操作数是 NaN |
NaN |
有一个操作数是 undefined |
undefined |
逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,就不会再对第二个操作数执行求值。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>逻辑与操作</title>
</head>
<body>
<script type="text/javascript">
var found = true;
var result = (found && someUnderfinedVariable); //报错
console.log(result);//不会执行
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>逻辑与操作(短路操作)</title>
</head>
<body>
<script type="text/javascript">
var found = false;
var result = (found && someUnderfinedVariable); //不会报错
console.log(result);//会执行
</script>
</body>
</html>
3.3 逻辑或
由 || 表示,规则如下:
第一个操作数 |
第二个操作数 |
结果 |
true |
true |
true |
true |
false |
true |
false |
true |
true |
false |
false |
false |
与逻辑与相似,如果有一个操作数不是布尔值,逻辑或就不一定返回布尔值,具体规则:
操作数类型 |
结果 |
第一个操作数是对象 |
返回第一个操作数 |
第一个操作数是求值结果为 false |
返回第二个操作数 |
两个操作数都是对象 |
返回第一个操作数 |
有一个操作数是 null |
null |
有一个操作数是 NaN |
NaN |
有一个操作数是 undefined |
undefined |
逻辑或操作也属于短路操作,即如果第一个操作数的求值结果为 true,就不会再对第二个操作数执行求值。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>逻辑或(短路操作)</title>
</head>
<body>
<script type="text/javascript">
var found = true;
var result = (found || someUnderfinedVariable); //不会报错
console.log(result);//不执行
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>逻辑与操作(短路操作)</title>
</head>
<body>
<script type="text/javascript">
var found = false;
var result = (found && someUnderfinedVariable); //不会报错
console.log(result);//会执行
</script>
</body>
</html>
可以利用逻辑或的这一行为来避免为变量赋值 null 或 undefined 值:
var myObject =
PReferredObejct || backupObject;
backupObject 可以在 preferredObejct 不包含有效值的情况下提供备用值。
程序的赋值语句经常会采用这样的模式。
4 乘性操作符
操作数如果是非数值,会自动执行类型转换。
4.1 乘法
由星号(*)表示,具体规则:
操作数类型 |
结果 |
都是数值 |
常规乘法运算,如果乘积超过表示范围,则返回 Infinity |
有一个操作数是 NaN |
NaN |
Infinity 与 0 相乘 |
NaN |
Infinity 与 非 0 数值相乘 |
Infinity |
Infinity 与 Infinity 相乘 |
Infinity |
有一个操作数不是数值 |
后台调用 Number() 转换为数值,在应用上面的规则 |
4.2 除法
由斜线(/)表示,具体规则:
操作数类型 |
结果 |
都是数值 |
常规除法运算,如果商超过表示范围,则返回 Infinity |
有一个操作数是 NaN |
NaN |
Infinity 被 Infinity 除 |
NaN |
0 被 0 除 |
NaN |
非零的有限数被 0 除 |
Infinity |
Infinity 与 非 0 数值除 |
Infinity |
有一个操作数不是数值 |
后台调用 Number() 转换为数值,再应用上面的规则 |
5 加性操作符
5.1 加法
操作数类型 |
结果 |
有一个操作数是 NaN |
NaN |
Infinity 加 Infinity |
Infinity |
-Infinity 加 -Infinity |
-Infinity |
+0 加 +0 |
+0 |
-0 加 -0 |
-0 |
+0 加 -0 |
+0 |
两个操作数都是字符串 |
第二个与第一个拼接 |
只有一个操作数是字符串 |
另一个字符串转换为字符串,再拼接 |
有一个操作数是对象、数值或布尔值 |
调用它的 toString() 方法取得字符串值,再按照字符串规则处理;对于nudefined 和 null,则调用 String() 取得 “undefined” 和 “null” |
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>加法</title>
</head>
<body>
<script type="text/javascript">
console.log(5+5);//10
console.log(5+"5");//55
</script>
</body>
</html>
忽视加法操作中的数据类型,是编程的常见错误(使用圆括号可以避免):
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>加法使用的常见错误</title>
</head>
<body>
<script type="text/javascript">
var num1 = 5;
var num2 = 10;
console.log("The sum of 5 and 10 is " + num1 + num2);//510
console.log("The sum of 5 and 10 is " + (num1 + num2));//15
</script>
</body>
</html>
5.2 减法
操作数类型 |
结果 |
两个操作数都是数值 |
常规减法 |
有一个操作数是 NaN |
NaN |
Infinity 减 Infinity |
NaN |
-Infinity 减 -Infinity |
-Infinity |
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() 并将得到的字符串转换为数值 |
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>减法操作</title>
</head>
<body>
<script type="text/javascript">
console.log(5 - true);//4;true 被转换为 1
console.log(NaN -1);//NaN
console.log(5 - 3);//2
console.log(5 - "");//5;"" 被转换为 0
console.log(5 - "2");//3
console.log(5 - null);//5;null 被转换为 0
</script>
</body>
</html>
6 关系操作符
当关系操作符使用了非数值时,就会进行数值转换,规则:
操作数类型 |
结果 |
两个操作数都是数值 |
数值比较 |
两个操作数都是字符串 |
比较两个字符串中对应的字符编码值 |
有一个操作数是数值 |
另一个操作数转换为数值,再比较 |
有一个操作数是对象 |
调用对象的 valueOf() ,再按照前面的规则执行比较;如果对象没有 valueOf() 方法,则调用 toString() 并将得到的结果进行比较 |
有一个操作数是布尔值 |
先转换为数值,再比较 |
注意:
用关系操作符比较两个字符串时,比较的是两个字符串中对应位置的每个字符的字符编码值。因此,如果要真正按字母表顺序比较字符串,就必须把两个操作数都转换为相同的大小写形式后,再进行比较。
比较数值的字符串形式时,比较的也是字符串编码。
任何操作数与NaN 比较,结果都是 false。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>关系操作符</title>
</head>
<body>
<script type="text/javascript">
console.log(5 > 3);//true
console.log(5 < 3);//false
//字符串比较的是字符串中对应位置的字符编码值,而大写字母的编码值都小于小写字母的字符编码
console.log("Brick" < "alphabet");//true
console.log("Brick".toLowerCase() < "alphabet".toLowerCase());//false;全部转为小写或者大写,这样就能按照字母表顺序比较
console.log("23" < "3");//true;数字字符串比较的还是字符编码
console.log("23" < 3);//false;其中一个操作数如果是数字,就会把另一个操作数也转为数字后,再进行比较
console.log("a" < 3);//false;非法数字的字符串会被转换为 NaN,任何操作数与 NaN 比较都是 false。
console.log(NaN < 3);//false
console.log(NaN >= 3);//false
</script>
</body>
</html>
7 相等操作符
7.1 相等(==)与不相等(!=)
会先转换(强制转换),再比较;转换规则:
操作数类型 |
结果 |
有一个操作数是布尔值 |
先转换为数值;false 转为 0,true 转为 1 |
一个操作数是字符串,另一个是数值 |
先将字符串转换为数值,再比较 |
一个操作数是对象,另一个不是 |
调用对象的 valueOf() 方法,再比较 |
比较规则:
null 和 undefined 是相等的。
比较相等性之前,不能将 null 和 undefined 转换成其他任何值。
有一个操作数是 NaN,则相等操作符返回 false;即使两个操作数都是 NaN,相等操作符也是返回 false(因为 NaN 不等于 NaN)。
如果两个操作数都是对象,则比较它们是不是同一个对象(即指向同一个对象)。
7.2 全等(===)与不全等
比较前不会自动转换:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>相等操作符</title>
</head>
<body>
<script type="text/javascript">
//全等和不全等与相等和不相等的唯一区别就是,在比较前不转换操作符
console.log("55" == 55);//true
console.log("55" === 55);//false
console.log("55" != 55);//false
console.log("55" !== 55);//true
</script>
</body>
</html>
注意:
null == undefined ,返回 true。
null === undefined,返回 false。
为了保证代码中数据类型的完整性,推荐使用全等和不全等操作符。
8 条件操作符
variable = boolean_expression ? true_value : false_value;
用于简化代码的编写
9 赋值操作符
赋值操作符是常规表达式的简化写法。
每个主要的算法操作符都有对应的复合赋值操作符。
只是简化代码,不会带来性能的提升。
10 逗号操作符
可以在一条语句中执行多个操作,多用于声明多个变量:
var num=1, num2=2, num3=3;