算术运算符
+ 、 - 、 * 、 / 、 ** 指数运算符、 %余数运算符、 ++x x++ 自增、 --x x--自减、+x数值运算符、负数值运算符。共10个。
- 所有的运算符中除了加法,其它都先将运算子转换成数值 再进行运算
加法
- 加法存在重载(overload):根据运算子不同有可能是'相加' 也可能是'连接'的现象。
true + true // 2
1 + true // 2
'a' + 'bc' // "abc"
1 + 'a' // "1a"
false + 'a' // "falsea" 如果一个运算子是字符串,另一个运算子是非字符串,这时非字符串会转成字符串,再连接在一起。
'3' + 4 + 5 // "345"
3 + 4 + '5' // "75"
- 对象相加
var obj = { p: 1 };
obj + 200 // "[object Object]200" 先调用对象的valueof方法返回原始值,再自动调用对象的toString将其转为字符串 再相加
但如果运算子是日期类型,那么会优先执行toString方法
let obj = new Date();
console.log(obj); //2021-03-18T03:35:18.833Z
obj + 1000; // 'Thu Mar 18 2021 11:35:18 GMT+0800 (中国标准时间)1000'
余数运算符 %
- 运算结果的正负号由第一个运算子的正负号决定
-1 % 2 // -1
1 % -2 // 1
自增自减
let x = 1;
let y = 1;
x++ // 1 先返回值 再自增
++y // 2 先自增 再返回值
数值运算符
- 数值运算符的作用在于可以将任何值转为数值,与Number函数的作用相同
+true // 1
+[] // 0
+{} // NaN
- 负数值运算符也可以将一个值转为数值,但是结果是负数 ,两个负数值运算符==数值运算符
var x = 1;
-x // -1
-(-x) // 1
指数运算符
- 指数运算符是右结合
// 相当于 2 ** (3 ** 2) 3的平方=9 2的9次方=512
2 ** 3 ** 2
// 512
赋值运算符
- 赋值运算符的变体
x += y // 等同于 x = x + y
x -= y // 等同于 x = x - y
x **= y // 等同于 x = x ** y
x >>= y // 等同于 x = x >> y
x <<= y // 等同于 x = x << y
x >>>= y // 等同于 x = x >>> y
x &= y // 等同于 x = x & y
x |= y // 等同于 x = x | y
x ^= y // 等同于 x = x ^ y
比较运算符
共8个比较运算符
>
大于运算符<
小于运算符<=
小于或等于运算符>=
大于或等于运算符==
相等运算符===
严格相等运算符!=
不相等运算符!==
严格不相等运算符
字符串的比较
JavaScript 引擎内部首先比较首字符的 Unicode 码点。如果相等,再比较第二个字符的 Unicode 码点,以此类推
'cat' > 'Cat' // true'
'大' > '小' // false 由于所有字符都有 Unicode 码点,因此汉字也可以比较。
非字符串的比较
- 如果是原型类型比较会先转换成数值再比较
true > false // true
// 等同于 Number(true) > Number(false)
// 即 1 > 0
2 > true // true
// 等同于 2 > Number(true)
// 即 2 > 1
- NaN与任何值比较返的都是false,包括他本身
NaN <= NaN // false
'1' <= NaN // false
- 如果是对象,则会转为原始类型的值,再进行比较
var x = [2];
x > '11' // true
// 等同于 [2].valueOf().toString() > '11'
// 即 '2' > '11'
console.log(x); //[ 2 ]
x.valueOf = function () { return '1' };
x > '11' // false
// 等同于 [2].valueOf() > '11'
// 即 '1' > '11'
console.log(x); //[ 2, valueOf: [Function] ]
[2] > [1] // true 两个对象之间的比较也是先转为原始类型的值,再比较
// 等同于 [2].valueOf().toString() > [1].valueOf().toString()
// 即 '2' > '1'
严格相等运算符
===
先比较类型,再比较值
- 同一类型的原始类型值
1 === 0x1 // true 十进制的1与十六进制的1,因为类型和值都相同,返回true
- 复合类型(对象 数组 函数)值的比较:
a.它们比较的不是值是否相等,而是比较它们是否指向同一个地址;
{} === {} // false
[] === [] // false
(function () {} === function () {}) // false
b.两个变量引用同一个对象,它们则相等
var v1 = {};
var v2 = v1;
v1 === v2 // true
//对于两个对象的比较,严格相等运算符比较的是地址,而大于或小于运算符比较的是值
- undefined和null与自身严格相等
undefined === undefined // true
null === null // true
相等运算符 ==
- 比较相同类型的数据时,与严格相等运算符完全一样
1 == 1.0
// 等同于
1 === 1.0
- 比较不同类型的数据,相等运算符会先将数据进行类型转换,再用严格相等运算符比较
a.原始类型值
1 == true // true
// 等同于 1 === Number(true)
0 == false // true
// 等同于 0 === Number(false)
2 == true // false
// 等同于 2 === Number(true)
2 == false // false
// 等同于 2 === Number(false)
'true' == true // false
// 等同于 Number('true') === Number(true)
// 等同于 NaN === 1
'' == 0 // true
// 等同于 Number('') === 0
// 等同于 0 === 0
'' == false // true
// 等同于 Number('') === Number(false)
// 等同于 0 === 0
'1' == true // true
// 等同于 Number('1') === Number(true)
// 等同于 1 === 1
'\n 123 \t' == 123 // true
// 因为字符串转为数字时,省略前置和后置的空格
b.对象与原始类型值比较
// 数组与数值的比较
[1] == 1 // true
// 数组与字符串的比较
[1] == '1' // true
[1, 2] == '1,2' // true
// 对象与布尔值的比较
[1] == true // true
[2] == true // false
//JavaScript 引擎会先对数组[1]调用数组的valueOf()方法,由于返回的还是一个数组,所以会接着调用数组的toString()方法,得到字符串形式再比较。
- undefined和null只有与自身比较,或者互相比较时,才会返回true;与其他类型的值比较时,结果都为false
undefined == null // true
false == null // false
- 相等运算符隐藏的类型转换,会带来一些违反直觉的结果,容易出错,建议使用严格相等
false == 'false' // false 因为是原始数据类型 会先转换成数值 再进行比较
false == '0' // true 相当于 Number(false) == "0";
布尔运算符
- 取反运算符:
!
- 且运算符:
&&
- 或运算符:
||
- 三元运算符:
?:
- 取反 !
a.对于非布尔值的取反,除了undefined、null、false、0、NaN、’‘ 取反的结果是true,其它都为false。
!'hello' // false
![] // false
!{} // false
b.两次取反就是将一个值转为布尔值的简便写法
!!x
//等同于
Boolean(x)
- 且 &&
a.运算规则:如果第一个运算子的布尔值为true,则返回第二运算子的值;如果第一个运算子的布尔值为false,则直接返回第一个运算子的值,且不再对第二个运算子求值。
't' && '' // ""
't' && 'f' // "f"
't' && (1 + 2) // 3
'' && 'f' // ""
'' && '' // ""
let x = 1;
1 - 1 && (x += 1); // 0
x; // 1 x的值没有被改变
// 这种跳过第二个运算子的机制,被称为“短路”, 可以用它来替换if结构
if (i) {
doSomething();
}
// 等价于
i && doSomething();
b.且运算符可以多个连用,这时返回第一个布尔值为false的表达式的值。如果所有表达式的布尔值都为true,则返回最后一个表达式的值。
true && 'foo' && '' && 4 && 'foo' && true;// ''
1 && 2 && 3; // 3
- 或 ||
a.如果第一个运算子的布尔值为true,则返回第一个运算子的值,且不再对第二个运算子求值;如果第一个运算子的布尔值为false,则返回第二个运算子的值
't' || '' // "t"
't' || 'f' // "t"
'' || 'f' // "f"
'' || '' // ""
b.短路规则对这个运算符也适用
var x = 1;
true || (x = 2) // true
x // 1
c.多个连用,这时返回第一个布尔值为true的表达式的值。如果所有表达式都为false,则返回最后一个表达式的值。
false || 0 || '' || 4 || 'foo' || true; // 4
false || 0 || ''; // ''
d.或运算符可以用于为变量设置默认值
function saveText(text) {
text = text || '';
// ...
}
// 或者写成
saveText(this.text || '')
// 上面代码表示,如果函数调用时,没有提供参数,则该参数默认设置为空字符串。
- 三元条件运算符
表达式 ? '表达式为true返回': '表达式为false返回'
其它运算符
- void运算符的作用是执行一个表达式,不返回任何值。主要用在浏览器的书签工具以及在超级链接中插入代码防止网页跳转
<a href="javascript: void(f())">文字</a>
<a href="javascript: void(document.form.submit())">
提交表单,但不跳转页面
</a>
- 逗号运算符: 用于对两个表达式求值,并返回后一个表达式的值。
var x = 0;
var y = (x++, 10);
x // 1
y // 10
圆括号的作用:
- 一种是把表达式放在圆括号之中,提升运算的优先级;
- 另一种是跟在函数的后面,作用是调用函数