深入解析JavaScript中的操作符:从基础到高级
引言
在 JavaScript 的编程世界中,操作符是我们日常编码不可或缺的一部分。它们不仅用于执行基本的数学运算,还用于比较值、逻辑判断、位操作等。理解这些操作符的工作原理和最佳实践,对于编写高效、健壮的代码至关重要。在本文中,我们将一起探索 JavaScript 中的各类操作符,包括它们的用法、优先级以及常见陷阱,帮助你更加熟练地运用它们来构建复杂而强大的应用程序。
运算元
运算元(Operands)指的是操作符操作的对象,也就是参与操作的数据。
- 一元操作符:需要一个运算元。例如,一元加和减(
+/-)
// 一元加由一个加号(+)表示,放在变量前面,对数值没有任何影响
var num = 25
num = +num
console.log(num)
// 一元减由一个减号(-)表示,放在变量前面,主要用于把数值变成负值
var num = 25
num = -num
console.log(num)
- 二元操作符:需要两个运算元。大多数操作符都属于这一类,如加法(
+)、减法(-)、乘法(*)等。
var diff = 15 - 10
console.log(diff) // 5
三元操作符:需要三个运算元。条件操作符是 JavaScript 唯一使用三个操作数的操作符。
// 语法格式:condition ? exprIfTrue : exprIfFalse
var a = 10, b = 20
var result = a > b ? a : b
console.log(result)
一元操作符
递增/递减操作符
将变量的值增加或减少 1
前置和后置的区别
递增和递减操作符可以放在变量的前面或后面,并且它们的行为有所不同
前置递增/递减(++x / --x)
先将变量的值增加/减少1,然后返回增加/减少后的值
var x = 5
console.log(++x) // 6 x 先自增,然后返回自增后的值
后置递增/递减(x++/x–)
先返回变量的当前值,然后将变量的值增加/减少1
var x = 5
console.log(x++) // 5 先返回 x 的当前值,然后 x 自增
console.log(x) // 6 显示 x 自增后的值
非整数递增/递减
- 对于字符串,如果是有效的数值形式,则转换为数值再应用改变
- 对于字符串,如果不是有效的数值形式,直接返回
NaN - 对于布尔值,
true转换为 1,false转换为 0 再应用改变 - 对于浮点值,加 1 或减 1
var s1 = "10"
var s2 = "12px"
var b1 = true
var b2 = false
var f = 1.1
// 10 + 1
console.log(++s1) // 11
// NaN + 1
console.log(++s2) // NaN
// 1 - 1
console.log(--b1) // 0
// 0 + 1
console.log(++b2) // 1
// 1.1 - 1
console.log(--f) // 0.10000000000000009
一元加操作符
不会改变数字的值,但如果用在非数字值前面,它会尝试将该值转换为数值
console.log(+12) // 12
console.log(+true) // 1
console.log(+false) // 0
console.log(+"12") // 12
console.log(+"1.2") // 1.2
console.log(+"") // 0
console.log(+undefined) // NaN
console.log(+null) // 0
一元减操作符
会改变数字的正负性,如果用在正数前面,它会变成负数;如果用在负数前面,它会变成正数
console.log(-true) // -1
console.log(-false) // -0
console.log(-"12") // -12
console.log(-"1.2") // -1.2
console.log(-"12px") // NaN
console.log(-undefined) // NaN
console.log(-null) // -0
逻辑操作符
逻辑非
首先将操作数转换为布尔值,然后再对其取反
console.log(!"Hello JavaScript") // false
console.log(!"") // true
console.log(!1) // false
console.log(!0) // true
console.log(!null) // true
console.log(!undefined) // true
console.log(!NaN) // true
console.log(!true) // false
console.log(!false) // true
console.log(!{}) // false
双重否定,将其他类型转为布尔类型
console.log(!!"") // false
console.log(!!"Hello") // true
console.log(!!1) // true
console.log(!!0) // false
console.log(!!undefined) // false
console.log(!!null) // false
console.log(!!NaN) // false
逻辑与
左右两个操作数都为真时,才返回真值。如果任一操作数为假,那么结果就是假
expr1 && expr2
如果 expr1 能被转换为 false,那么返回 expr1,否则返回 expr2。在逻辑与操作中,expr1 为假时不会执行 expr2(短路行为)
常被用于条件执行
var obj = {
condition: true,
message: "Hello"
}
obj.condition && console.log(obj.message)
逻辑或
左右两个操作数至少有一个为真时,返回真值。只有当两个操作数都为假时,结果才是假
expr1 || expr2
如果 expr1 能被转换为 true,那么返回 expr1,否则返回 expr2。在逻辑或操作中,expr1 为真时不会执行 expr2(短路行为)
常用于为变量提供默认值
// 为变量提供默认值
var uname = ""
var findName = uname || "默认用户名"
console.log(findName) // 默认用户名
算数操作符
算术操作符以二个数值(字面量或变量)作为操作数,并返回单个数值
加法操作符
连接字符串或计算数字之和
数值加法
console.log(2 + 3) // 5
console.log(-2 + 3) // 1
console.log(-2 + -2) // -4
特殊值参与运算
- 如果有任一操作数是
NaN,则返回NaN - 如果是
Infinity加Infinity,则返回Infinity - 如果是
-Infinity加-Infinity,则返回-Infinity - 如果是
Infinity加-Infinity,则返回NaN
console.log(NaN + 1) // NaN
console.log(Infinity + Infinity) // Infinity
console.log(-Infinity + -Infinity) // -Infinity
console.log(Infinity + -Infinity) // NaN
非数值加法
如果操作数是非字符串的基本类型,先在后台使用 Number() 将其转 换为数值,然后再执行数学运算
// 1 + 0 = 1
console.log(true + false) // 1
// 1 + 0 = 1
console.log(true + null) // 1
// 0 + NaN = NaN
console.log(false + undefined) // NaN
字符串连接
只要任一操作数为字符串类型,则自动将另一个操作数转为字符串类型,执行字符串拼接操作
console.log("Hello" + " " + "World!") // "Hello World!"
// "2" + "2"
console.log(2 + "2") // "22"
// "false" + "true"
console.log(false + "true") // falsetrue
// "" + "undefined"
console.log("" + undefined) // "undefined"
// "" + null
console.log("" + null) // "null"
// 5 + "4"
console.log(2 + 3 + "4") // "54"
减法操作符
计算两个数字之差
数值减法
console.log(5 - 3) // 2
console.log(3 - 5) // -2
特殊值参与运算
-
如果有任一操作数是
NaN,则返回NaN -
如果两个操作数都是无限值
- 符号相同,返回
NaN - 符号不同,返回第一个操作数
- 符号相同,返回
console.log(5 - NaN) // NaN
console.log(Infinity - Infinity) // NaN
console.log(-Infinity - -Infinity) // NaN
console.log(Infinity - -Infinity) // Infinity
console.log(-Infinity - Infinity) // -Infinity
非数值减法
如果有任一操作数是非数值的基本数据类型,先在后台使用 Number() 将其转 换为数值,然后再执行数学运算
// 5 - 1
console.log(5 - true) // 4
// 1 - 0
console.log(true - false) // 1
// 5 - 0
console.log(5 - "") // 5
// 5 - 2
console.log(5 - "2") // 3
// 5 - 0
console.log(5 - null) // 5
// 5 - NaN
console.log(5 - undefined) // NaN
乘法操作符
计算两个数字之积
数值乘法
console.log(2 * 3) // 6
console.log(2 * -3) // -6
console.log(-2 * -3) // 6
特殊值参与运算
-
如果有任一操作数是
NaN,则返回NaN -
如果是
Infinity乘以 0,则返回NaN -
如果是
Infinity乘以非 0 的有限数值,则根据第二个操作数的符号返回Infinity或-Infinity -
如果两个操作数都是无限值
- 符号相同,返回
Infinity - 符号不同,返回
-Infinity
- 符号相同,返回
console.log(NaN * 1) // NaN
console.log(Infinity * 0) // NaN
console.log(Infinity * 2) // Infinity
console.log(Infinity * -2) // -Infinity
console.log(Infinity * Infinity) // Infinity
console.log(-Infinity * -Infinity) // Infinity
console.log(Infinity * -Infinity) // -Infinity
console.log(-Infinity * Infinity) // -Infinity
非数值乘法
先在后台使用 Number() 转型函数,将其转换为数值
// 1 * 2
console.log(true * 2) // 2
// 0 * 5
console.log(false * 5) // 0
// 10 * 3
console.log("10" * "3") // 30
// 0 * 5
console.log("" * 5) // 0
// NaN * 2
console.log(undefined * 2) // NaN
// 0 * 3
console.log(null * 3) // 0
除法操作符
计算两个数字的商
数值除法
console.log(66 / 11) // 6
console.log(-66 / -11) // 6
console.log(-66 / 11) // -6
特殊值参与运算
- 如果有任一操作数是
NaN,则返回NaN - 如果是 0 除以 0,则返回
NaN - 如果是非 0 的有限值除以 0,则根据第一个操作数的符号返回
Infinity或-Infinity - 如果是
Infinity除以任何有限值,根据第二个操作数的符号返回Infinity或-Infinity - 如果两个操作数都是无限值,返回
NaN
console.log(2 / NaN) // NaN
console.log(Infinity / Infinity) // NaN
console.log(0 / 0) // NaN
console.log(5 / 0) // Infinity
console.log(-5 / 0) // -Infinity
console.log(Infinity / 2) // Infinity
console.log(Infinity / -2) // -Infinity
console.log(Infinity / -0) // -Infinity
非数值除法
先在后台使用 Number() 转型函数将其转换为数值
// 1 / 2
console.log(true / 2) // 0.5
// 0 / 5
console.log(false / 5) // 0
// 10 / 3
console.log("10" / "3") // 3.3333333333333335
// 0 / 5
console.log("" / 5) // 0
// NaN / 2
console.log(undefined / 2) // NaN
// 0 / 3
console.log(null / 3) // 0
取模操作符
计算两个数字的余数
数值取模
console.log(9 % 3) // 0
console.log(-9 % 2) // -1
console.log(1 % 3) // 1
特殊值参与运算
- 如果被除数是无限值,除数是有限值,则返回
NaN - 如果第二个操作数为 0,返回
NaN - 如果第一个操作数小于第二个操作数,返回第一个操作数
- 如果两个操作数都为无限值,返回
NaN
console.log(Infinity % 5) // NaN
console.log(-Infinity % 5) // NaN
console.log(5 % 0) // NaN
console.log(Infinity % Infinity) // NaN
console.log(-Infinity % -Infinity) // NaN
console.log(Infinity % -Infinity) // NaN
console.log(-Infinity % Infinity) // NaN
console.log(5 % Infinity) // 5
console.log(-5 % Infinity) // -5
console.log(0 % 3) // 0
非数值取模
先在后台使用 Number() 转型函数将其转换为数值
// 1 % 0
console.log(true % false) // NaN
// 0 % 1
console.log(false % true) // 0
// NaN % 0
console.log(undefined % null) // NaN
// 0 % 4
console.log(null % 4) // 0
// 9 % 2
console.log(9 % "2") // 1
指数操作符
返回第一个操作数取第二个操作数的幂的结果
基本求幂
console.log(2 ** 3) // 8
console.log(3 ** 2) // 9
console.log(16 ** 0.5) // 4
// 如果操作数不是数值,先在后台使用 Number() 转型函数将其转换为数值
console.log("3" ** "2")
结合性
// 2 ** (3 ** 2)
console.log(2 ** 3 ** 2) // 512
console.log((2 ** 3) ** 2) // 64
关系操作符
比较两个值之间的关系,根据比较的结果返回一个布尔值
小于操作符
检查左侧的操作数是否小于右侧的操作数
console.log(2 < 10) // true
console.log(10 < 2) // false
当比较不同类型的值时,会尝试进行类型转换
- 如果操作数都是字符串,则逐个比较字符串中对应字符的编码
- 如果有任一操作数是数值,则将另一个操作数转换为数值
- 如果有任一操作数是布尔值,则将其转换为数值再执行比较
// "2":字符编码为 50
// "1":字符编码为 49
// 50 < 49
console.log("2" < "10") // false
// 2 < 10
console.log(2 < "10") // true
// 0 < 1
console.log(false < true) // true
大于操作符
检查左侧的操作数是否大于右侧的操作数
console.log(10 > 2) // true
console.log(2 > 10) // false
当比较不同类型的值时,与其他关系操作符一致
// 97 > 98
console.log("a" > "b") // false
// 4 > 3
console.log("4" > 3) // true
// NaN > 3
console.log("abc" > 3) // false
// 0 > 1
console.log(null > true) // false
小于等于操作符
检查左侧的操作数是否小于或等于右侧的操作数
console.log(3 <= 3) // true
console.log(3 <= 4) // true
console.log("a" <= "b") // true
console.log(undefined <= null) // false
console.log(true <= false) // false
大于等于操作符
检查左侧的操作数是否大于或等于右侧的操作数
console.log(3 >= 3) // true
console.log(3 >= 4) // false
console.log("a" >= "b") // false
console.log(undefined >= null) // false
console.log(true >= false) // true
相等操作符
相等操作符
检查其两个操作数是否相等,返回一个布尔值结果。会比较不同类型的操作数,并尝试强制类型转换
console.log(5 == 5) // true
console.log(5 == "5") // true
当尝试类型转换时会遵循如下规则:
- 如果任一操作数是布尔值,则将其转换为数值再比较是否相等
- 如果一个操作数是字符串,另一个操作数是数值,尝试将字符串转换为数值
null和undefined相等null和undefined不能转换为其他类型的值再进行比较- 如果有任一操作数是
NaN,直接返回false
// 1 == 2
console.log(true == 2) // false
// 10 == 10
console.log(10 == "10") // true
// null 和 undefined 是相等的
console.log(null == undefined) // true
// 不能转为其他类型
console.log(null == 0) // false
// 不能转为其他类型
console.log(undefined == "undefined") // false
不等操作符
检查其两个操作数是否不相等,并返回布尔结果。它会转换并比较不同类型的操作数
console.log(1 != 2) // true
console.log("Hello" != "hello") // true
console.log(1 != 1) // false
console.log("Hello" != "Hello") // false
console.log(1 != `1`) // false
console.log(null != 0) // true
console.log(true != 1) // false
全等操作符
检查两个操作数是否相等且数据类型是否相同,并返回布尔结果
console.log(10 === "10") // false
console.log(null === undefined) // false
console.log(6 === 6) // true
非全等操作符
与全等操作符相反
console.log("Hello" !== "Hello") // false
console.log("Hello" !== "hello") // true
console.log(1 !== true) // true
console.log(3 !== "3") // true
条件操作符
格式为 条件 ? 表达式1 : 表达式2。如果条件为真,执行表达式1,否则执行表达式2
var age = 26
var beverage = age >= 21 ? "Beer" : "Juice"
console.log(beverage) // "Beer"
赋值操作符
赋值操作符将右边的操作数的值分配给左边的操作数
简单赋值
简单赋值操作符(=)用于给变量赋值
// 简单赋值
var a = 10
var b = 20
// 链式
var x, y, z
x = y = z = 20
console.log(x, y, z) // 20 20 20
复合赋值
复合赋值使用乘性、加性或位操作符后跟等于号(=)表示。这些赋值操作符是类似如下常见赋值操作的简写形式
var num = 10
num = num + 10
// 以上代码的第二行可以通过复合赋值来完成
var num = 10
num += 10
每个算数操作符以及其他一些操作符都有对应的复合赋值操作符:
- 乘后赋值(*=)
- 除后赋值(/=)
- 取模后赋值(%=)
- 加后赋值(+=)
- 减后赋值(-=)
- 求幂后赋值(**=)
注意:这些操作符仅仅是简写语法,使用它们不会提升性能
操作符的优先级
总结
JavaScript 中的操作符丰富多样,涵盖了从基础算术到高级位操作的各个方面。熟练掌握这些操作符的用法、优先级和常见陷阱,对于提升编程效率和代码质量具有重要意义。通过本文的深入解析,希望你能更加自信地运用 JavaScript 中的操作符来构建出更加出色的应用程序。