0. 检测类型操作符
0.1 typeof
多用于基本类型检测,返回值有 string
、number
、boolean
、undefined
、object
、function
检测
null
会返回object
检测函数时会返回
function
0.2 instanceof
用于检测对象类型
result = variable instanceof constructor;
所有引用类型的值都是
Object
的实例,在检测引用类型值和Object
构造函数时,instanceof
操作符始终返回true
使用
instanceof
操作符检测基本类型的值时,始终返回false
1. 算术操作符
1.1 递增、递减
分为前置和后置
前置放在变量之前,表示先对变量加减
1
后再进行变量的其他操作后置放在变量之后,表示一条语句结束后再对变量加减
1
对任何值都适用,包括字符串、布尔值、浮点数值和对象
包含有效数字字符的字符串时,先将其转换为数值,在执行加减
1
操作,字符串变量变成数值变量不包含有效数字字符时,将变量的值设置为
NaN
,字符串变量变成数值变量布尔值,
false
变换成0
,true
变换成1
,再进行加减1
操作,布尔值变成数值变量浮点数值,直接进行加减
1
操作对象,先调用对象的
valueOf()
方法以取得一个可供操作的值,应用前面的规则,如果结果为NaN
,再调用对象的toString()
方法后再应用前面的规则。对象变量变成数值变量
注意:n++ 和 n = n + 1 一样吗? 当 n 是数字或其它类型的时候,是一样的 而当 n 是字符串时,一个依然是数学运算,另一个却是字符串拼接
var n = '10'
n = n + 1; //=> n: '101'
n++ //=> n: 11
1.2 一元加减
在对非数值应用一元加或减操作符时,会像 Number()
转型函数一样执行转换
var s = "01";
s = +s; //s=1;
{} + 'aa' //=> NaN,原因在于 {} 会被解析为代码块,后面就只是 + 'aa',就是一元加
({}) + 'aa' //=> '[object Object]aa',这时就是字符串拼接
一元减主要用于表示负数
2. 位操作符
位操作符应用于最基本的层次上,按内存中表示数值的位来操作数值,同样效果中,速度更快
所有数值以 IEEE-754 64 位格式存储
默认情况下,所有的整数都是有符号整数
当数值应用位操作符时
64
位数值被转换成32
位数值执行位操作
将
32
位数值转换为64
位数值副效应:对特殊的
NaN
和Infinity
值应用位操作时,会被当0
处理
对非数值应用位操作
- 自动使用
Number()
函数转换为数值,然后应用位操作
- 自动使用
注意:在内存中,负数是以二进制补码的格式存储的,但是在将负数以二进制字符串形式输出时,我们看到的是负数的绝对值的二进制码前面加一个负号,而不是以补码形式展现。
2.1 按位非 ~
返回数值的反码,本质是操作数是负值减 1
2.2 按位与 &
两个数值的每一位对齐,对应位都是 1
时才返回 1
,任何一位是 0
,结果都是 0
2.3 按位或 |
两个数值的每一位对齐,对应位有一个是 1
就返回 1
,都是 0
时返回 0
2.4 按位异或 ^
两个数值的每一位对齐,对应位只有一个 1
时才返回 1
,都是 1
或都是 0
,则返回 0
2.5 左移 <<
将数值的所有位向左移动指定位数
以
0
来填充空位,以便得到完整的32
位二进制数左移不会影响到符号位
2.6 有符号右移 >>
将数值向右移动指定位数
保留符号位
用符号位的数来填充所有空位,以便得到完整的值
2.7 无符号右移 >>>
以
0
来填充空位对正数的有符号右移和无符号右移是一样的
对负数进行无符号右移会把负数的二进制码当成正数的二进制码,导致结果非常之大
3. 布尔操作符
3.1 逻辑非 !
应用于任何值,先将操作数转换成布尔值,再对其求反
规则:实际上先对操作数应用 Boolean()
转换为布尔值,然后再取反
同时使用两个逻辑非操作符,实际上就会模拟
Boolean()
函数的行为,用于将一个值转换为与其对应的布尔值
3.2 逻辑与 &&
可以应用于各种类型的操作数,而不仅仅是布尔值
在有一个操作数不是布尔值时,就不一定返回布尔值了
规则:
第一个操作数不是布尔值,则使用
Boolean()
进行转换,是布尔值,则直接判断结果为
true
,则返回第二个操作数结果是
false
,则返回第一个操作数。如果第一个操作数是
false
,返回false
如果第一个操作数是
null
,返回null
如果第一个操作数是
NaN
,返回NaN
如果第一个操作数是
undefined
,返回undefined
如果第一个操作数是
''
,返回''
如果第一个操作数是
0
,返回0
短路操作:如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值
var found = true;
var result = (found && someUndefined);//发生错误
alert(result);//这一行不会执行
var found = false;
var result = (found && someUndefined);//不会发生错误
alert(result);//执行结果 false
回调函数:传值是函数时,让函数执行
function fn(callback) {
//=> 如果传递的值是一个函数,我们让其执行
// if(typeod callback === 'function') {
// callback()
// }
callback && callback(); //=> 如果 callback 存在则执行它
//=> 这种写法是不够严谨的,但是经常使用。因为约定好,默认 callback 要不然就传函数,要不然就不传。
}
fn(function() {})
3.3 逻辑或 ||
规则:
第一个操作数不是布尔值,则使用
Boolean()
进行转换,是布尔值,则直接判断结果为
true
,则返回第一个操作数结果是
false
,则返回第二个操作数
短路操作:如果第一个操作数的求值结果为
true
,那么就不会再对第二个操作数求值
赋值语句经常采用这种模式:用以给参数赋默认值
var myObject = preferredObject || backupObject;
虽然不够严谨,但是在真实项目中约定俗称,经常使用。因为默认要么不传值,要么传递的就是所需要的值。所以在需要传递的值为假的时候,应该避免这种默认值定义方式
4. 乘性操作符
在操作数为非数值的时候会执行自动类型转换,先使用 Number()
转型函数将其转换为数值
4.1 乘法 *
规则:
乘积超过数值的表示范围,则返回
Infinity
或-Infinity
有一个操作数是
NaN
,则结果为NaN
Infinity
与0
相乘,结果为NaN
Infinity
与非0
数值相乘,结果为Infinity
或-Infinity
Infinity
与Infinity
相乘,结果为Infinity
操作数不是数值,则在后台调用
Number()
将其转换为数值,再应用上面的规则
4.2 除法 /
规则:
商超过数值的表示范围,则返回
Infinity
或-Infinity
有一个操作数是
NaN
,则结果为NaN
Infinity
被Infinity
除,结果为NaN
非
0
的有限数被0
除,结果是Infinity
或-Infinity
Infinity
被任何数值除,结果是Infinity
或-Infinity
操作数不是数值,则在后台调用
Number()
将其转换为数值,再应用上面的规则
4.3 求模 %
求余数
规则:
都是数值,执行常规除法,返回除得的余数
被除数是
Infinity
,除数是有限数值,结果返回NaN
被除数是有限数值,除数是
0
,结果是NaN
Infinity
被Infinity
除,结果是NaN
被除数是有限大的数值,除数是
Infinity
,结果是被除数被除数是
0
,结果是0
操作数不是数值,则在后台调用
Number()
将其转换为数值,再应用上面的规则
4.4 幂 **
幂运算符返回第一个操作数做底数,第二个操作数做指数的乘方。即 $ var1^{var2} $,其中 var1 和 var2 是其两个操作数。
幂运算符是右结合的。a ** b ** c
等同于 a ** (b ** c)
。
包括 PHP 或 Python 等的大多数语言中,都包含幂运算符(一般来说符号是 ^
或者 **
)。这些语言中的幂运算符有着比其他的单目运算符(如一元 + 或一元 - )更高的优先级。但是作为例外,在 Bash 中,**
运算符被设计为比单目运算符优先级更低。在最新的 JavaScript(ES2016) 中,禁止使用带歧义的幂运算表达式。比如,底数前不能紧跟一元运算符(+/-/~/!/delete/void/typeof
)
-2 ** 2;
// 在 Bash 中等于 4 ,而在其他语言中一般等于 -4
// 在 JavaScript 中是错误的,因为这会有歧义
-(2 ** 2);
// -4 在JavaScript中能够明显体现出作者的意图
示例
2 ** 3 // 8
3 ** 2 // 9
3 ** 2.5 // 15.588457268119896
10 ** -1 // 0.1
NaN ** 2 // NaN
2 ** 3 ** 2 // 512
2 ** (3 ** 2) // 512
(2 ** 3) ** 2 // 64
如果要反转求幂表达式结果的符号,你可以采用这样的方式:
-(2 ** 2) // -4
强制求幂表达式的基数为负数:
(-2) ** 2 // 4
5. 加性操作符
5.1 加法 +
规则:
操作数是
NaN
,返回NaN
Infinity
加Infinity
,结果是Infinity
-Infinity
加-Infinity
,结果是-Infinity
Infinity
加-Infinity
,结果NaN
操作数是字符串
都是字符串,进行拼接
只有一个是字符串,另一个转换为字符串,进行拼接
操作数是对象、数值、布尔值,调用
toString()
方法取得相应的字符串值操作数是
undefined
和null
,调用String()
函数取得字符串值
5.2 减法 -
规则:
操作数是
NaN
,返回NaN
Infinity
减Infinity
,结果是NaN
-Infinity
加-Infinity
,结果是NaN
Infinity
加-Infinity
,结果Infinity
-Infinity
加Infinity
,结果-Infinity
操作数是字符串、布尔值、
null
、undefined
,先在后台调用Number()
函数转换为数值,在按上面规则执行操作数是对象,调用对象的
valueOf()
方法取得对象的数值,如果结果是NaN
,则减法的结果是NaN
。如果没有valueOf()
方法,则调用其toString()
方法将其得到的字符串转换为数值
6. 关系操作符
关系操作符有:<、>、<=、>=
规则:
两个数都是数值,则执行数值的比较
都是字符串,比较两个字符串对应的字符编码值
一个是数值,则将另一个也转换为数值,执行比较
一个是对象,调用对象的
valueOf()
方法取得对象的数值,如果没有valueOf()
方法,则调用其toString()
方法将其得到的字符串转换为数值布尔值,将其转换为数值执行比较
操作数存在
NaN
或者undefined
、null
,结果都是false
7. 相等操作符
7.1 相等与不相等 ==
规则:
先转换后比较
布尔值,转换为数值再比较
一个字符串,一个数值,则将字符串转换为数值再比较
都是字符串,比较两个字符串对应的字符编码值
一个是对象,另一个是字符串,则将对象转换为字符串再比较
都是对象,则比较是不是同一对象,如果指向同一对象,则相等返回
true
其他都是转换为数值再比较
null
和undefined
是相等的有
NaN
,使用相等结果都是false
,使用不相等结果都是true
,NaN
不等于任何值,包括自身
1==true //=> true
1==false //=> false
2==true //=> false
[] == 0 //=> true,都转换为数字
[] == '0' //=> false,左边转换为字符串 '',再比较
{} == '[object Object]' //=> true,左边先转换为字符串,再比较
[]==false //=> true,都转换为数字
[]==true //=> false,都转换为数字
![]==false //=> true,先算 ![] 为 false,再比较
![]==true //=> false,先算 ![] 为 false,再比较
7.2 全等和不全等 ===
只在两个操作数未经转换就相等的情况下才返回 true
,也就是类型和值都要相等。真实项目中为了保证代码的严谨性,应该更多的使用严格相等。
8. 条件、赋值、逗号
8.1 条件操作符 ? :
variable = boolean_expression ? true_value : false_value
可以执行多条语句,用小括号包裹,不同语句用逗号隔开;也可以不执行任何语句,用 null
undefined
等占位
var num = 12;
num > 10 ? (num++, num*=10) : null;
8.2 赋值操作符 =
简单的赋值操作符由等号表示,如果在等号前面再添加乘性操作符、加性操作符或位操作符,就变成了复合操作符。
*=
/=
%=
+=
-=
<<=
=
=
设计这些操作符的主要目的是简化赋值操作,使用它们不会带来任何性能的提升。
8.2 逗号操作符,
使用逗号操作符可以在一条语句中执行多个操作
var num = 1, num2 = 2, num3 = 3;
多用于声明多个变量,但除此之外,还可以用于赋值,在用于赋值时,逗号操作符总会返回表达式中的最后一项。
var num = (5, 1, 4, 0); //=> num: 0
在三元运算符中,也可以使用逗号来分隔多条语句