本文以《JavaScript高级程序设计》第4版作为参考,整理使用JavaScript开发过程中,使用操作符相关的知识点。
本文是开发知识点系列第四篇。
在我看来操作符和语句都是逻辑的具体体现,不同的是操作符颗粒度更细。JavaScript中的操作符是独特的,因为它们可以应用各种值,包括字符串、数值、布尔值,甚至对象。在应用对象时,操作符通常会调用valueOf()
和/或toString()
方法来取得可以计算的值。
一元操作符
只操作一个值的操作符叫一元操作符。
递增/递减操作符
递增++
,递减--
。这两个主要是用于数值计算。可以有前置和后置之分。前置先进行操作符操作,后赋值;后置先赋值操作,再进行操作符操作。
该操作符也是可以进行数值转换的,但我感觉不常用,我没有这样用过。都是确定是数字的情况使用该操作符。
一元加和减
一元加和减是好理解的,因为这俩有点像九年义务教育学习的正号+和负号-。我对这俩的应用相对来说也比较少。
一元加号,放在变量为数值的前面没有任何影响。如果放在非数值前面,会执行与使用Number()转型函数一样的类型转换。Number()转换规则可以看我的第三篇关于开发的文章:JavaScript开发:使用Number数据类型需要注意的问题
一元减号,放在变量为数值的前面表示数值为负值。一元减放在非数值前面,会遵循和一元加一样的规则。
位操作符
位操作符种类不少:按位非、按位与、按位或、按位异或、左移、无符号右移、有符号右移。但在实际开发中,我使用的不多,我知道有按位与判断奇偶性
js
// 是否为奇数
function isOdd(num) {
return (num & 1) === 1;
}
// 判断是否为偶数
function isEven(num) {
return (num & 1) === 0;
}
console.log(isOdd(5)); // true
console.log(isEven(5)); // false
console.log(isOdd(4)); // false
console.log(isEven(4)); // true
双按位非操作符对一个数进行取整。也可以用于字符串,如果不能取整,则返回0。
js
console.log(~~'123'); // 123
console.log(~~'123px'); // 0
console.log(~~'123.456'); // 123
console.log(~~'abc'); // 0
布尔操作符
布尔操作符:逻辑非、逻辑与、逻辑或。这三个操作符可以说经常被用到。逻辑与与逻辑或都有短路特性。
逻辑非的基本逻辑是首先将操作数转为布尔值,然后在对其取反。这个操作符始终返回布尔值。
在实际开发中,逻辑非的使用多用于条件逻辑。逻辑与用于判断或者执行条件逻辑。逻辑或多是设置默认值以及作为条件判断。
布尔操作符也可以用于其他数据类型。以下是一些数据转换规则:
以下值在转换为布尔值时为false
:
false
0
和-0
NaN
""
(空字符串)null
undefined
所有其他值在转换为布尔值时都为true
,包括所有对象(包括空对象{}
和空数组[]
)和所有非空字符串。
以下是一些例子:
javascript
console.log(true && 'yes'); // 'yes'
console.log(false && 'yes'); // false
console.log(true || 'yes'); // true
console.log(false || 'yes'); // 'yes'
console.log(!true); // false
console.log(!0); // true
console.log(!'abc'); // false
console.log(!''); // true
console.log(![]); // false
console.log(!{}); // false
需要注意的是,虽然逻辑与和逻辑或操作符会将操作数转换为布尔值,但它们的结果是原始的操作数,而不是转换后的布尔值。
乘性操作符
乘性操作符:乘法操作符、除法操作符、取模操作符。这三个比较好理解,而且应用起来也比较简单,简单来说就是九年义务教育的知识。其中取模就是取余数。
指数操作符
指数操作符**,可以替代原有的Math.pow()
函数。指数操作符就是用来进行指数操作。
加性操作符
加性操作符:加法操作符和减法操作符。不同于九年义务教育的加法或者减法。JavaScript的加法操作符除了可以进行加法运算,还可以用拼接字符串,如果操作数有一个是字符串就会按照进行字符串拼接操作。
而对于减法操作符,如果有任一操作符是字符串、布尔值、null
或者undefined
,则先使用Number()
将其转为数值,然后再进行减法操作。
注意:要确保进行加法减法操作的数值在有效范围内。
关系操作符
关系操作符:小于<,大于>,小于等于<=和大于等于>=。在我的项目开发中用的并不多。该操作符用法和数学课本上的学的一致,这几个操作符都返回布尔值。都可以应用到非数值类型,这时会进行数值转换,转换逻辑如下
- 如果两个操作数都是对象,JavaScript会调用它们的
toString
方法(如果存在)来将它们转换为字符串,然后比较字符串。如果toString
方法不存在,JavaScript会尝试调用valueOf
方法。 - 如果一个操作数是对象,另一个操作数是数值,JavaScript会尝试调用对象的
valueOf
方法来将对象转换为数值,然后比较数值。如果valueOf
方法不存在或者返回的不是一个原始值,JavaScript会调用toString
方法。 - 如果一个操作数是对象,另一个操作数是字符串,JavaScript会将两个操作数都转换为字符串,然后比较字符串。
- 如果两个操作数都是字符串,JavaScript会按照字典顺序比较字符串。
- 如果两个操作数都是数值,或者可以被转换为数值,JavaScript会比较数值
- 如果任意操作数是布尔值,则将其转换为数值再执行比较
相等操作符
相等操作符:等于、不等于和全等。这个平时用的也一般。也可以用于其他类型数值的比较。也会有数据转换逻辑在里面,当然转换主要发生在等于和不等于使用时。转换规则
- 全等(===):不进行类型转换,如果两个操作数的类型不同,那么它们不相等。如果两个操作数的类型相同,那么比较它们的值。对于基本类型(数值、字符串和布尔值),如果值相同,那么它们相等;对于对象,如果它们引用的是同一个对象,那么它们相等。
- 等于(==)和不等于(!=):会进行类型转换,以下是一些规则: 如果两个操作数的类型相同,那么比较它们的值,规则和全等相同。 如果一个操作数是数值,另一个操作数是字符串,那么将字符串转换为数值,然后比较数值。 如果一个操作数是布尔值,那么将布尔值转换为数值(
true
转换为1,false
转换为0),然后比较数值 如果一个操作数是对象,另一个操作数是数值或字符串,那么将对象转换为原始值(通过调用对象的valueOf
或toString
方法),然后比较原始值。null
和undefined
相等。null
和undefined
不等于任何其他值。NaN
不等于任何值,包括它自己
条件操作符
条件操作符,这里的条件操作符说的是三元运算法。是实际开发中使用最为广泛的操作符之一。
条件(三元)操作符(condition ? exprIfTrue : exprIfFalse
)在进行运算时,会首先将condition
转换为布尔值。以下是一些规则:
- 如果
condition
是布尔值,那么直接使用这个值。 - 如果
condition
是null
、undefined
、NaN
、0、-0
或空字符串(""
),那么它会被转换为false
。 - 如果
condition
是任何其他值,包括所有对象(包括数组)和非空字符串,那么它会被转换为true
。
然后,根据condition
的值,条件操作符会计算并返回exprIfTrue
或exprIfFalse
。这两个表达式的类型转换规则取决于它们的具体用法。
以下是一些例子:
javascript
console.log(true ? 'yes' : 'no'); // 'yes'
console.log(false ? 'yes' : 'no'); // 'no'
console.log(null ? 'yes' : 'no'); // 'no'
console.log('abc' ? 'yes' : 'no'); // 'yes'
console.log(0 ? 'yes' : 'no'); // 'no'
console.log([] ? 'yes' : 'no'); // 'yes'
赋值操作符
赋值操作符:'=',可以说应用的最为频繁。还可以与其它符号复合使用,不做过多介绍。
逗号操作符
逗号操作符也就是逗号',',用于在一条语句里面执行多个操作。
其它操作符
其他操作符,比如new
、delete
、in
等。
操作符的优先级
操作符的优先级决定了表达式中操作的顺序。优先级高的操作符会先被计算。
以下是一些常见操作符的优先级,从高到低:
- 圆括号:
( )
- 成员访问:
.
或[]
- 新建实例:
new
(带参数列表) - 函数调用:
()
- 逻辑非:
!
- 乘法、除法、取余:
*
、/
、%
- 加法、减法:
+
、-
- 关系比较:
<
、<=
、>
、>=
- 相等比较:
==
、!=
、===
、!==
- 逻辑与:
&&
- 逻辑或:
||
- 条件(三元)操作符:
? :
- 赋值:
=
- 逗号:
,
如果在表达式中同时出现了多个优先级不同的操作符,那么优先级高的操作符会先被计算。如果优先级相同,那么通常会从左到右进行计算,但也有一些例外,例如赋值和条件操作符是从右到左计算的。
可以使用圆括号来改变操作的顺序,因为圆括号的优先级最高,圆括号中的表达式总是会先被计算。
关于操作符中的数据类型转换
上面一元操作符、布尔操作符、乘性操作符、指数操作符、加性操作符、关系操作符、相等操作符(全等除外)、条件操作符都可以进行数据类型转换。并且转换规则并不完全相同。
所以我的建议是如果使用的操作符潜在存在进行数据类型转换的可能性,那么尽量用不发生数据转换的数据使用操作符。要不然就彻底搞清楚这些操作符的内在转换逻辑。
也正因为存在数据转换。有些面试场景下,有人会重写对象的valueOf()
或toString()
作为面试题,考返回值是什么,这种题本质是对数据转换的拦截。
总结一下
- 一元操作符使用要提前确定好数据类型,避免数据转换
- 可以使用位操作符
&
判断奇偶性 - 可以使用位操作符
~
取整 - 逻辑非总是返回布尔值
- 逻辑与和路逻辑都有短路特性,而且它们的结果是原始的操作数,而不是转换后的布尔值
- 乘法操作符和指数操作符也是要提前确定好数据类型,避免数据转换
- 加性操作符可以用于拼接字符串也可以进行加法运算,作为加法运算使用时注意避免数据转换
- 关系操作符最好只用于数值和字符串减少不确定性
- 相等操作符注意相等和不相等的数据转换逻辑
- 条件操作符的
condition
会提前转换为布尔类型,这个就放心了 - 操作符的优先级需要知道,如果不清楚就用圆括号改变
本文完。