JavaScript 操作符

javascript

JavaScript 操作符

JavaScript 支持多种操作符/运算符,且不同数据类型可支持的运算符和运算含义也不同。

JavaScript 支持的常见操作符

  • 算术操作符
  • 逻辑操作符
  • 赋值操作符
  • 比较操作符
  • 三元操作符,一般用于条件语句

需要厘清几个核心概念:

  • 运算元:运算符应用的对象,也称参数。
  • 一元运算符:一个运算符对应只操作有一个运算元,如 unary negation 一元负号运算符 -
  • 二元运算符:一个运算符拥有两个运算元,如减号运算符 -
Tip

按位操作符是将其操作数当作最多为 32 位的比特序列(由0和1组成,而不是十进制、十六进制或八进制数值)进行操作,并返回标准的 JavaScript 数字,具体运算规则可查看 按位操作符 - JavaScript | MDN 文档。

运算符优先等级

如果一个表达式拥有超过一个运算符,执行的顺序则由优先级决定

JavaScript 中每个运算符都有对应的优先级数字,数字越大越先执行,如果优先级相同,则按照由左至右的顺序执行。

Tip

要记住一元运算符优先级高于二元运算符

算术运算

JavaScript 控制台支持计算数字公式,常用的算术运算符

  • 加法 +
  • 减法 -
  • 乘法 * ⚠️ 不是 x
  • 除法 /(在 Java 中是整除)
  • 乘方 ** 即幂运算,对于运算元是非整数的情况依然适用,如 a ** (1/2) 相当于开方。 ⚠️ 日常数学公式中的乘方符号 ^ 在是指按位 XOR
  • 取模 % modulo 即求余

比较运算

比较数值的比较运算符

运算符含义备注
<小于/
>大于/
<=小于或等于/
>=大于或等于/
==等于比较值是否相等(比较前可能进行隐式转换)
===全等于同时比较数据类型和值是否相等
!=不等于比较值是否不相等(比较前可能进行隐式转换)
!==不全等同时比较数据类型和值是否不相等(只要其中一个不相同就是不全等)

数字之间的比较结果是布尔值 truefalse,比较的结果可以被赋值给任意变量

Tip

当对不同类型的值进行比较时,JavaScript 会首先将其转化为数字 number 类型,再判定大小。

  • 比较字符的大小时,JavaScript 会使用 Unicode 编码顺序进行判定,而对于字符串时是按从左往右依次比较字符(母)。
    字符串的比较算法步骤:
    1. 首先比较两个字符串的首位字符大小。
    2. 如果一方字符较大(或较小),则该字符串大于(或小于)另一个字符串。算法结束。
    3. 否则,如果两个字符串的首位字符相等,则继续取出两个字符串各自的后一位字符进行比较。
    4. 重复上述步骤进行比较,直到比较完成某字符串的所有字符为止。
    5. 如果两个字符串的字符同时用完,那么则判定它们相等,否则未结束(还有未比较的字符)的字符串更大。
    js
    alert( 'Z' > 'A' ); // true
    alert( 'Glow' > 'Glee' ); // true
    alert( 'Bee' > 'Be' ); // true
    
  • nullundefined 比较行为很特别。
    当使用非严格相等 == 比较 null 空值和 undefined 未定义时,JavaScript 存在一个特殊的规则,会判定它们相等。
    js
    alert( null == undefined ); // true
    

    当使用数学式或其他比较方法 < > <= >=时(不包括 ==!=,由于相等性检测比较特殊,与其他比较运算符行为不一样)nullundefined 会被分别转化为数字 0NaN
    js
    // null 转换为 0
    alert( null > 0 );   // false
    alert( null >= 0 );   // true
    
    // null 不转换为 0
    alert( null == 0 );   // false
    
    alert( undefined > 0 ); // false
    alert( undefined < 0 ); // false
    alert( undefined == 0 ); // false
    
    Tip

    undefinednull 在相等性检测 ==!=不会进行任何的类型转换,且undefined 只与 null 相等,不会与其他值相等。

Warning

由于比较不同类型的值时,处于判断符号 ==!= 两侧的值会先被转化为数字,隐式类型转换引起不可预料的结果。推荐使用绝对比较运算符则比较时不会做任何的类型转换。

Warning

由于 nullundefined 特殊的比较行为,对于取值可能是 nullundefined 的变量,请按需要分别检查它的取值情况。

字符串连接

二元运算符加号 + 被应用于字符串,将合并(连接)各个字符串。只要其中一个运算元是字符串,那么另一个运算元也将被转化(数据隐式类型转换)为字符串

js
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
Tip

如果想在连接的两个字符串之间留个空格,需要明确地在添加(使用引号把空格包括插在两者之间),解析器不会自动添加

Warning

运算符运算方向根据运算符的不同优先级别而定,或同级别的运算符由左至右运算,因此如果是两个数字相加,后面再连接一个字符串,那么两个数字会先进行算术运算,再转化为字符串与其后的字符串连接

js
"Hello" + 5*10   // "Hello50"
alert(2 + 2 + '1' );   // "41" 而不是 "221"
Tip

除了加法,其余的算术运算符对于字符串和数值之间的计算,会先将字符串进行隐式转换为数值在进行运算;而加法则是进行字符串的拼接(即数字会被隐式转换为字符串)。

赋值运算符

赋值运算符将右侧的值「写入」左侧的变量,对于链式赋值也是由右向左执行。

Tip

每个运算符都有一个返回值,赋值符号返回左侧的值。

数字转换

一元运算符加号,即加号 + 应用于单个值,会将其转化为数字(对数字没有任何作用),相当于 Number() 函数。

逗号运算符

逗号运算符能让我们处理多个语句,使用 , 将它们分开,每个语句都运行了,但是只有最后的语句的结果会被返回。

js
// 在 for 循环的条件判断中,一行上用逗号分隔了三个算式
for (a = 1, b = 3, c = a * b; a < 10; a++) {
 ...
}

自增和自减

  • 自增:x++ or ++x 等同于 x = x + 1
  • 自减:x-- or --x 等同于 x = x - 1
Tip

自增/自减的优先级比绝大部分的算数运算符要高。

前置自增 ++x 和后置自增 x++ 在返回值的行为上有所不同

  • 前置自增 ++x 返回新值,即计算后再返回新值。
  • 后置自增 x++返回原来的值,即先返回原值再自增。

一般它们只有在使用自增式子的返回值作为表达式一部分时才有区别,若只是需要自增 x 值则两种方式均可。因此如果我们想要对变量进行自增操作,并且需要立刻使用自增后的值,那么我们需要使用前置形式;如果我们想要将一个数加一,但是我们想使用其自增之前的值,那么我们需要使用后置形式。自减也是类似。

js
// 前置自增
let counter = 1;
let a = ++counter;
alert(a);   // 2
alert(counter);   // 2

// 后置自增
let counter = 1;
let a = counter++;
alert(a);   // 1
alert(counter);   // 2
Warning

自增/自减只能应用于变量

修改并替换

对一个变量进行操作,并把计算得到的新结果存储在原来的这个变量中,可以使用简写形式:

Tip

简短的“修改并替换”运算符对所有的运算符包括位运算符都有效,如 /=等等。

常用的简写形式

  • 增加简写:x += 3 等同于 x = x + 3
  • 减少简写 x -= 6 等同于 x = x - 6
  • 相乘简写:x *= 2 等同于 x = x * 2
  • 相除简写:x /= 5 等同于 x = x / 5

逻辑运算符

JavaScript 里有三个逻辑运算符:

  • || 或,优先级别最低
  • &&与,优先级别为中
  • ! 非,优先级别最高
Tip

逻辑表达式基于优先级别(默认)从左到右进行条件判断,可以用括号来更改运算的优先级别。

这些运算符操作布尔值组合并返回相应的布尔值作为结果。

逻辑运算符含义示例解释
&&逻辑 ANDvalue1 && value2只有 value1value2 都为 true,才返回 true
``逻辑 OR
!逻辑 NOT!value1返回 value1 的相反值
Tip

如果操作数不是布尔值,那么它将会被隐式转化为布尔值来参与运算,则返回值就不一定是布尔值,如对于两个操作数的 && 运算,可以用于选择性地返回特定的值(基于短路规则)

  • 如果第一个操作数隐式类型转换后为 true,则返回第二个操作数
  • 如果第一个操作数隐式类型转换后为 false,则返回第一个操作数
js
let value = 80 && 55;   // 赋值为 55,而不是 true
let value2 = 0 && 55;   // 赋值为 0,而不是 false
let str = "hello" && 65 && "abc"   // 赋值为字符串 abc

如果存在特殊的值,有 nullNaNundefined 之一,对于多个操作数执行 && 运算,当前面的操作数隐式类型转换后都为 true,其后的值遵循特定规则(基于短路规则)

  • 如果有一个操作数是 null,则返回 null
  • 如果有一个操作数是 NaN,则返回 NaN
  • 如果有一个操作数是 undefined,则返回 undefined

或运算 || 是指参与运算的任意一个参数为 true,返回的结果就为 true,否则返回 false

js
// 或运算真值表,四种可能的逻辑组合
true || true;   // true
false || true;  // true
true || false;  // true
false || false; // false

也支持非布尔值(进行隐式类型转换)组合运算,💡 可以用于 if 语句中,用多个 || 并列串联不同的条件语句,构成复杂的判断情况

js
if (1 || 0) { // 工作原理相当于 if( true || false )
  alert( 'truthy!' );   // 弹出一个模态窗口显示 truthy!
}

与运算 && 是指当两个操作数都是真值才返回 true,否则返回 false

js
// 与运算真值表,四种可能的逻辑组合
true && true;   // true
false && true;  // false
true && false;  // false
false && false; // false

就像或运算一样,可以支持任意类型的值组合运算,并返回 false 相对应的参数。

短路

使用 &&|| 逻辑运算符时,出现的逻辑表达式的后续参数不用考虑的行为就叫做最少运算短路,因为前面的参数已经满足条件了。

&& 与 || 运算的真假值表
&& 与 || 运算的真假值表

在特定的情况下,后一个条件 B 的布尔值不重要:

  • 当第一个条件 A 布尔值为 false 时,那么无论第二个条件 B 的值是多少,A && B 整个表达式始终为 false,则在该情况下不须考虑条件 B 的情况。
  • 当第一个条件 A 布尔值为 true 时,那么无论第二个条件 B 的值是多少,A || B 整个表达式始终为 true,则在该情况下不须考虑条件 B 的情况。

利用短路特性,可以实现短路取值,即通过一个逻辑链为变量赋予特定的值:

  • 一个或运算 || 链,将返回第一个真值,如果没有真值就返回最后一个值。
  • 一个与运算 && 链,将返回第一个假值,如果没有假值就返回最后一个值。
js
let currentUser = null;
let defaultUser = "John";

let name = currentUser || defaultUser || "unnamed";   // 返回第一个真值或最后一个值

alert( name );   // John

非运算 ! 是指返回参数的相反的布尔值。

Tip

可以使用两个非运算 !! 来将某个值转化为布尔类型,类似于 Boolean() 函数


Copyright © 2024 Ben

Theme BlogiNote

Icons from Icônes