操作符
基础概念
- 操作符:也叫运算符,是一种符号。通过操作符可以对一个或多个值进行运算,并获取运算结果
- 表达式:由数字、运算符、变量的组成的式子,一个表达式往往会产生一个值
一元操作符
只操作一个值的操作符叫一元操作符
递增/递减操作符
++是递增操作符,表示在自身基础上加 1
a++先用再加,++a 先加再用
var a = 3
var b = ++a
console.log(b) // 4
var a = 3
var b = a++
console.log(b) // 3
递减操作符同理,不做赘述
另外,这 4 个操作符可以作用于任何值,意思是不限于整数——字符串、布尔值、浮点值,甚至对象都可以。 递增和递减操作符遵循如下规则:
- 对于字符串,如果是有效的数值形式,则转换为数值再应用改变。变量类型从字符串变成数值。
- 对于字符串,如果不是有效的数值形式,则将变量的值设置为 NaN。变量类型从字符串变成数值。
- 对于布尔值,如果是 false,则转换为 0 再应用改变。变量类型从布尔值变成数值。如果是 true,则转换为 1 再应用改变。变量类型从布尔值变成数值。
- 对于浮点值,加 1 或减 1。
- 如果是对象,则调用其 valueOf()方法取得可以操作的值。对得到的值应用上述规则。如果是 NaN,则调用 toString()并再次应用其他规则。变量类型从对象变成数值。
let a = {
valueOf() {
return -1
},
}
a-- // 值变成2
一元加和减
一元加由一个加号(+)表示,放在变量前头,对数值没有任何影响
如果将一元加应用到非数值,则会执行与使用 Number()转型函数一样的类型转换:布尔值 false 和 true 转换为 0 和 1,字符串根据特殊规则进行解析,对象会调用它们的 valueOf()和/或 toString()方法以得到可以转换的值。
一元减由一个减号(-)表示,放在变量前头,主要用于把数值变成负值
在应用到非数值时,一元减会遵循与一元加同样的规则,先对它们进行转换,然后再取负值
一元加和减操作符主要用于基本的算术,但也可以像上面的例子那样,用于数据类型转换。
布尔操作符
布尔操作符的优先级是:非 → 与 → 或,而在 js 表达式中的优先级是:非 → 数学(乘性,加性)→ 关系 → 布尔,例如:
!5 < 4 + 4 || 3 < 1 // true
逻辑非
逻辑非操作符由一个叹号(!
)表示,这个操作符始终返回布尔值,无论应用到的是什么数据类型。逻辑非操作符首先将操作数转换为布尔值,然后再对其取反。 逻辑非操作符会遵循如下规则:
- 如果操作数是对象,则返回 false。
- 如果操作数是空字符串,则返回 true。
- 如果操作数是非空字符串,则返回 false。
- 如果操作数是数值 0,则返回 true。
- 如果操作数是非 0 数值(包括 Infinity),则返回 false。
- 如果操作数是 null,则返回 true。
- 如果操作数是 NaN,则返回 true。
- 如果操作数是 undefined,则返回 true。
逻辑非操作符也可以用于把任意值转换为布尔值。同时使用两个叹号(!!
),相当于调用了转型函数 Boolean()
逻辑与
逻辑与操作符由两个和号(&&
)表示,应用到两个值,两个值都真才真
逻辑或
逻辑或操作符由两个管道符(||)表示,两个值有真就真
短路运算
a&&b
- 如果 a 是真的,b 的真假决定结果,b 真结果就真,b 假结果就假,所以它的结果就是 b
- 如果 a 是假的,不用看 b 了,被短路了。结果就是 a
3 && 6 // 6
null && 2 // null
a||b
- 如果 a 是真的,不用看 b 了,被短路了。结果就是 a
- 如果 a 是假的,b 的真假决定结果,b 真结果就真,b 假结果就假,所以它的结果就是 b
如果出现布尔运算符连续的情况
先计算前面的结果,拿这个结果和后面的进行计算:
false || false || 123
=>123
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}
乘性操作符
ECMAScript 定义了 3 个乘性操作符:乘法、除法和取模。
乘法操作符由一个星号(*)表示,可以用于计算两个数值的乘积。
除法操作符由一个斜杠(/)表示,用于计算第一个操作数除以第二个操作数的商
取模操作符
取模操作符用百分号“%″表示
a%b
表示求 a 除以 b 的余数,它不关心整数部分,只关心余数
指数操作符
ECMAScript 7 新增了指数操作符
,Math.pow()
现在有了自己的操作符**
,结果是一样的:
console.log(Math.pow(3, 2); // 9
console.log(3 ** 2);// 9
加性操作符
字符串拼接的几种情况
const a = 100 + 10
const b = 100 + '10' // 只要有一个不是数字,就是字符串拼接
const c = true + 10
console.log(a, b, c) // 110 10010 11
加性操作符,即加法和减法操作符
加法操作符有“加法”和“连字符”两种作用,如果加号两边的操作数都是数字,则为“加法”
如果有一方是字符串的话,加号的作用就是将他们进行拼接,在这种情况下,另一操作数是对象、数值或布尔值,则调用它们的 toString()方法以获取字符串,对于 undefined 和 null ,则调用 String() 函数, 分别获取 "undefined"和"null"
如果加号两边均是布尔值、null 或 undefined,则先在后台使用 Number()将其转换为数值,然后再执行数学运算。如果转换结果是 NaN,则计算的结果是 NaN;如果有任一操作数是对象,则调用其 valueOf()方法取得表示它的数值。如果该值是 NaN,则计算的结果是 NaN。如果对象没有 valueOf()方法(Math 和 Error 对象没有 valueOf 方法),则调用其 toString()方法,然后再将得到的字符串转换为数值
减法操作符,除了基本的数学运算外,只要有一个操作数是字符串、布尔值、null 或 undefined,则先在后台使用 Number()将其转换为数值,然后再执行数学运算。如果转换结果是 NaN,则减法计算的结果是 NaN;如果有任一操作数是对象,则调用其 valueOf()方法取得表示它的数值。如果该值是 NaN,则减法计算的结果是 NaN。如果对象没有 valueOf()方法,则调用其 toString()方法,然后再将得到的字符串转换为数值
一道 NT 面试题
'a' + +'b' // -> "aNaN"
因为 + 'b' 等于 NaN,所以结果为 "aNaN"
关系操作符
关系操作符执行比较两个值的操作,包括小于(<
)、大于(>
)、小于等于(<=
)和大于等于(>=
),这几个操作符都返回布尔值
- 如果操作数都是数值,则执行数值比较。
- 如果操作数都是字符串,则逐个比较字符串中对应字符的编码。
- 如果有任一操作数是数值,则将另一个操作数转换为数值,执行数值比较。
- 如果有任一操作数是对象,则调用其 valueOf()方法,取得结果后再根据前面的规则执行比较。如果没有 valueOf()操作符,则调用 toString()方法,取得结果后再根据前面的规则执行比较。
let a = {
valueOf() {
return 0
},
toString() {
return '1'
},
}
a > -1 // true
在以上代码中,因为 a 是对象,所以会通过 valueOf 转换为原始类型再比较值。
- 如果有任一操作数是布尔值,则将其转换为数值再执行比较。
js 中没有连比
2 < a <= 15 // ❌
a > 2 && a <= 15 // √
相等操作符
两个等号==运算符不比较值的类型,它会进行隐式转换后比较值是否相等
三个等号===运算符,不仅比较值是否相同,也比较类型是否相同,只有两个操作数在不转换的前提下相等才返回 true。
在转换操作数的类型时,相等
和不相等操作符
遵循如下规则:
- 如果任一操作数是布尔值,则将其转换为数值再比较是否相等。
false
转换为 0,true
转换为 1。 - 如果一个操作数是字符串,另一个操作数是数值,则尝试将字符串转换为数值,再比较是否 相等。
- 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法取得其原始值,再根据前面的规则进行比较。
在进行比较时,这两个操作符会遵循如下规则:
- null 和 undefined 相等。
- null 和 undefined 不能转换为其他类型的值再进行比较。
- 如果有任一操作数是 NaN,则相等操作符返回 false,不相等操作符返回 true。记住:即使两 个操作数都是 NaN,相等操作符也返回 false,因为按照规则,NaN 不等于 NaN。
- 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回 true。否则,两者不相等。 全等和不全等操作符与相等和不相等操作符类似,只不过它们在比较相等时不转换操作数。
条件操作符
var a = b ? 1 : 2
上面的代码执行了条件赋值操作,即根据条件表达式 b 的值决定将哪个值赋 给变量 a 。如果 b 是 true ,则赋值 1 ;如果 b 是 false,则赋值 2。
赋值操作符
简单赋值用等于号(=)表示,将右手边的值赋给左手边的变量
每个数学操作符以及其他一些操作符都有对应的复合赋值操作符:
- 乘后赋值(*=)
- 除后赋值(/=)
- 取模后赋值(%=)
- 加后赋值(+=)
- 减后赋值(-=)
新增
空值合并运算符当左侧的操作数为 null
或者undefined
时,返回其右侧操作数,否则返回左侧操作数
与逻辑或运算符||
不同,逻辑或运算符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 ||
来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如,''
或 0
)时
let a = 0;
console.log(a || '/'); // 本意是只要 a 为 null 或者 Undefined 的时候,输出 '/',但实际上只要是假值就输出 '/'
可选链式操作符
可选链运算符(?.
)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?.
运算符的功能类似于 .
链式运算符,不同之处在于,在引用为空( null
或者 undefined
)的情况下不会引起错误,该表达式短路返回值是 undefined
。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined
。
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const dogName = adventurer.dog?.name;
console.log(dogName);
// Expected output: undefined
console.log(adventurer.someNonExistentMethod?.());
// Expected output: undefined