||&&与短路运算符

假值:

  • false
  • null
  • undefined
  • NaN
  • 0(包括+0,-0,0n)
  • '' 空字符串

||(一真则真)

|| 先依次进行布尔判定,返回第一个真值,而且不会再进行后面的比较与计算;如果都是假值则返回最后一个值

应用:默认值设置 ||

1
2
3
let value = possiblyUndefinedVariable || 'default value';
// 如果possiblyUndefinedVariable的值为真,那就把possiblyUndefinedVariable的值赋给value
// 但如果possiblyUndefinedVariable的值为假,那就把默认值'default value'赋给value

&&(一假则假)

先依次进行布尔判定,返回第一个假值,而且不会再进行后面的比较与计算;如果都是真值则返回最后一个值

应用:&&短路运算代替 if

1
2
3
4
5
6
7
8
if (condition) {
executeFunction();
}

//简化为
condition && executeFunction();
// 如果condition为假则直接返回condition不会执行executeFunction()
// 如果condition为真才会执行executeFunction()

应用:安全的对象属性访问

使用 && 运算符可以避免在访问嵌套属性时由于中间的对象不存在而抛出的 TypeError。 这就是所谓的”安全的对象属性访问”。(访问不到也不会报错)

1
2
3
4
5
6
7
8
let value = obj && obj.prop && obj.prop.subProp;
// 首先检查 obj 是否存在(即 obj 不是 undefined 或 null)。
// 如果存在,那么就继续检查 obj.prop;
// 如果 obj 不存在,那么 obj && obj.prop && obj.prop.subProp 的结果就是 undefined,
// 并且由于 && 的短路特性,不会尝试访问 obj.prop。
// 同样,obj.prop && obj.prop.subProp 首先检查 obj.prop 是否存在。
// 如果 obj.prop 存在,那么就返回 obj.prop.subProp;如果 obj.prop 不存在,
// 那么就返回 undefined,并且不会尝试访问 obj.prop.subProp。

?.Optional Chaining (可选链)

对于上面“安全的对象属性访问”的例子,?.提供了一种更简洁的方式来安全地访问深层次的对象属性。

1
2
3
let value = obj?.prop?.subProp || 'default value';
// 如果 obj 或 obj.prop 为 undefined 或 null,那么整个表达式的值就会是 'default value'。
// 只有 obj 或 obj.prop都为真的时候,才会返回obj.prop.subProp。

??空值合并运算符

??类似于 ||运算符,但只在左边的操作数为 null undefined 时,才会返回右边的操作数

它比||更加细化,||只能看真假,而??具体到nullundefined

1
2
3
4
let value = possiblyZeroOrEmptyString ?? 'default value';
// 只有当 possiblyZeroOrEmptyString 为 null 或 undefined 时,value 才会被设置为 'default value'。
// 如果 possiblyZeroOrEmptyString 为 0 或空字符串,value 的值就会是 0 或空字符串。
// 如果使用||,那么如果 possiblyZeroOrEmptyString 为 0 或空字符串,value的值也会是undefined。

算数运算符

+, -, *, /, %, **

数字运算

纯数字之间正常数学运算,但要注意numberBigInt之间不能混合运算,而且BigInt的运算与number相同,但除法会省略小数部分

1
2
3
4
5
6
7
8
9
10
11
12
13
console.log(3 + 7); //10
console.log(3 - 7); //-4
console.log(3 * 7); //21
console.log(3 / 7); //0.42857142857142855
console.log(3 % 7); //3
console.log(2 ** 2); //4
console.log(4 + 5n); //报错:Cannot mix BigInt and other types, use explicit conversions
console.log(3n + 7n); //10n
console.log(3n - 7n); //-4n
console.log(3n * 7n); //21n
console.log(7n / 3n); //2n
console.log(3n % 7n); //3n
console.log(2n ** 2n); //4n

特殊字面量参与运算

NaN

与任何值进行算术运算(除了字符串连接),结果都是 NaN NaN 与任何值(包括 NaN 自身)进行比较的结果都是 false

1
2
3
4
5
6
7
console.log(NaN + 3); //NaN
console.log(NaN - 3); //NaN
console.log(NaN * 3); //NaN
console.log(NaN / 3); //NaN
console.log(NaN % 3); //NaN
console.log(NaN ** 3); //NaN
console.log(NaN + ''); //'NaN'

Infinity-Infinity

当超过 JavaScript 数字的最大值时,会产生 Infinity,当超过最小值时,会产生 -Infinity。 它们参与的运算,视情况而定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
console.log(Infinity + 3); //Infinity
console.log(Infinity - 3); //Infinity
console.log(Infinity * 3); //Infinity
console.log(Infinity / 3); //Infinity
console.log(Infinity % 3); //NaN
//
onsole.log(-Infinity + 3); //-Infinity
console.log(-Infinity - 3); //-Infinity
console.log(-Infinity * 3); //-Infinity
console.log(-Infinity / 3); //-Infinity
console.log(-Infinity % 3); // NaN
//
console.log(3 / Infinity); // 0
console.log(3 % Infinity); // 3
console.log(3 / -Infinity); // -0
console.log(3 % -Infinity); // 3
//
console.log(Infinity + Infinity); //Infinity
console.log(-Infinity - Infinity) //-Infinity
console.log(Infinity - Infinity); //NaN
console.log(-Infinity - Infinity) //NaN
console.log(Infinity * Infinity); //Infinity
console.log(Infinity / Infinity); //NaN
console.log(Infinity % Infinity); //NaN

undefined

与任何值进行算术运算时,结果都是 NaN除了字符串连接外

在 JavaScript 中,undefined 隐式转换为以下值:

  1. undefined 参与数学运算时,会被转换为 NaN (非数字)
  2. undefined字符串拼接时,会被转换为字符串 "undefined"
  3. undefined布尔运算时,会被转换为 false
  4. undefined对象比较时,通常会被转换为 null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
console.log(undefined + 3); //NaN
console.log(undefined - 3); //NaN
console.log(undefined * 3); //NaN
console.log(undefined / 3); //NaN
console.log(undefined % 3); //NaN
console.log(undefined ** 3); //NaN

console.log(undefined + undefined); //NaN
console.log(undefined - undefined); //NaN
console.log(undefined * undefined); //NaN
console.log(undefined / undefined); //NaN
console.log(undefined % undefined); //NaN
console.log(undefined ** undefined); //NaN

console.log(undefined + null); //NaN
console.log(undefined - null); //NaN
console.log(undefined * null); //NaN
console.log(undefined / null); //NaN
console.log(undefined % null); //NaN
console.log(undefined ** null); //1 在JS中任何数的0次幂都为1,包括0,null,NaN,undefined,Infinity,-Infinity

console.log(undefined + ''); //'undefined'

null

与任何值进行算术运算时, null 会被转换为数字 0

1
2
3
4
5
6
7
8
9
10
11
12
13
console.log(null + 3); //3
console.log(null - 3); //-3
console.log(null * 3); //0
console.log(null / 3); //0
console.log(null % 3); //0
console.log(null ** 3); //0

console.log(null + null); //0
console.log(null - null); //0
console.log(null * null); //0
console.log(null / null); //NaN
console.log(null % null); //NaN
console.log(null ** null); //1 在JS中任何数的0次幂都为1,包括0,null,NaN,undefined,Infinity,-Infinity

其他类型的数据参与数学运算

加法

如果有一个操作数是NaN,那么结果为NaN除了字符串会变成字符串(只有加法会这样——拼接)外,其他都会先进行隐式类型传唤再进行计算。

1
2
3
4
5
6
7
8
9
10
11
console.log('10' + 1); // '101'
console.log('' + 1); // '1'
console.log(1 + 2 + '3'); // '33'
console.log('' + true) // 'true'
console.log('' + NaN) // 'NaN'
console.log('' + undefined) // 'undefined'
console.log('' + null) // 'null'
console.log('' + Infinity) // 'Infinity'
console.log('' + -Infinity) // '-Infinity'
console.log('' + [1,2,3]) // '1,2,3'
console.log('' + {a:1,b:2}) // '[object Object]'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
console.log(1 + NaN); // NaN  (Number)
console.log(1 + true); // 2 (Number)
console.log(1 + false); // 1 (Number)
console.log(1 + null); // 1 (Number)
console.log(1 + undefined); // NaN (Number)
console.log(1 + []); // '1' 数组会先转成用,连接的字符串再进行拼接
console.log([] + 1); // '1'
console.log([] + []); // ''
console.log(1 + [1,2,3]); // '11,2,3'
console.log(1 + {}); // '1[object Object]' 对象会先转成用字符串'[object Object]'再进行拼接
console.log({} + 1); // '[object Object]1'
console.log({} + {}); // '[object Object][object Object]'
console.log(1 + {name:'li'}); // '1[object Object]'
console.log([] + {}); // '[object Object]'
console.log({} + []); // '[object Object]'
console.log([1,2,3] + {name:'li'}); // '1,2,3[object Object]'
console.log(new Date() + 1); // 'Fri Jul 09 2021 10:36:29 GMT+0800 (中国标准时间)1'
// JavaScript 会尝试将日期对象转换为字符串。
// 对象的 toString() 方法会被调用,返回日期对象的字符串表示形式,例如 "Fri Jul 09 2021 10:36:29 GMT+0800 (中国标准时间)"。
// 然后,JavaScript 将这个字符串与数字进行字符串拼接。

减法

先将其他类型隐式转成number类型再进行计算,如果转不了则变成NaN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
console.log(1 - NaN); // NaN  (Number)
console.log(1 - true); // 0 (Number)
console.log(1 - false); // 1 (Number)
console.log(1 - null); // 1 (Number)
console.log(1 - undefined); // NaN (Number)
console.log(1 - []); // 1 空数组会转成0
console.log([] - 1); // -1
console.log([] - []); // 0
console.log(1 - [12]); // -11 数组中元素只有1个时,会将其隐式转化成number类型再进行运算
console.log(1 - [null]); // 1
console.log(1 - [undefined]); // 1
console.log(1 - [NaN]); // NaN
console.log(1 - [Infinity]); // -Infinity
console.log(1 - [-Infinity]); // Infinity
console.log(1 - [[]]); // 1
console.log(1 - [[1]]); // 0
console.log(1 - [{}]); // NaN
console.log(1 - [1,2,3]); // NaN 数组中元素数量超过1(>=2)时会转成NaN
console.log(1 - {}); // NaN 对象隐式转化后都是NaN,不论是空还是非空对象
console.log({} - 1); // NaN
console.log({} - {}); // NaN
console.log(1 - {name:'li'}); // NaN
console.log([] - {}); // NaN
console.log({} - []); // NaN
console.log([1,2,3] - {name:'li'}); // NaN
console.log(new Date() - 1);
// 从一个日期对象中减去一个数字时,JavaScript 会将该数字解释为毫秒数,并将这些毫秒数从日期对象的时间戳中减去。

乘法

和减法一样:先将其他类型隐式转成number类型再进行计算,如果转不了则变成NaN

除法

也和减法一样:先将其他类型隐式转成number类型再进行计算,如果转不了则变成NaN

但要注意:除以0(或隐式转化成0)为Infinity ,除以Infinity为0,除以-Infinity为-0

取模

  • 如果左右两侧均是数值,则进行除法计算,结果返回余数
  • 任何一侧为NaN,则结果返回NaN
  • 只要除数是0(或隐式转化成0) ,则结果返回NaN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
console.log(1 % NaN); // NaN  (Number)
console.log(1 % true); // 0 (Number)
console.log(1 % false); // NaN
console.log(1 % null); // NaN
console.log(1 % undefined); // NaN
console.log(1 % []); // 1 NaN
console.log([] % 1); // 0
console.log([] % []); // NaN
console.log(1 % [12]); // 1
console.log(1 % [null]); // NaN
console.log(1 % [undefined]); // NaN
console.log(1 % [NaN]); // NaN
console.log(1 % [Infinity]); // 1
console.log(1 % [-Infinity]); // 1
console.log(1 % [[]]); // NaN
console.log(1 % [[1]]); // 0
console.log(1 % [{}]); // NaN
console.log(1 % [1,2,3]); // NaN
console.log(1 % {}); // NaN
console.log({} % 1); // NaN
console.log({} % {}); // NaN
console.log(1 % {name:'li'}); // NaN
console.log([] % {}); // NaN
console.log({} % []); // NaN
console.log([1,2,3] % {name:'li'}); // NaN
console.log(new Date() % 1);
// 对一个日期对象取模时,JavaScript 会隐式地将日期对象转换为其对应的时间戳(毫秒数)。
// 然后,JavaScript 会计算时间戳对给定数字的余数。

加号+与减号-

  • 操作数是Number类型,无影响(不论是正号还是负号,对NaN都是无影响
  • 操作数是其他类型,它具有转化成Number类型的功能 +a效果与Number(a) 相同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
console.log(+'21') // 21
console.log(-'21') // 21
console.log(+[]); // 0
console.log(+[1]); // 1
console.log(+[1,2]); // NaN [1,2]原始值为'1,2',转化为Number类型为NaN
console.log(+{}); // NaN
console.log(-undefined) // NaN

let str = '123';
console.log(str + 2); // 1232
console.log(+str + 2); // 125 => '123'转化为Number类型

let num1 = 10;
let num2 = 20;
console.log(num1 + num2); // 30
console.log(num1 + '' + num2); // 1020 => 转化为字符串拼接

自增与自减

  • 前置型++a先自增再使用
  • 后置型a++先使用再自增
  • 如果有一侧不为Number类型,则(根据对应的规则)转为数字类型后,再进行计算

比较运算符

字符 说明
> 大于
< 小于
>= 大于等于
<= 小于等于

规则:

  1. 如果左右两侧都是数值,则数值之间进行比较
  2. 如果左右两侧都是字符串,则根据字符串对应的字符编码值
  3. 如果有一侧是NaN,则结果得到false
  4. 如果是nullundefinedtruefalse,则(会根据对应的规则)进行转换,然后进行比较
  5. undefined > < <= >=与任何值比较时都为false
  6. 任何与 NaN 进行的比较运算(无论是使用 > < >= <= 还是 == === )都会返回 false 。这是因为 NaN 不等于任何值,包括它自己。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
console.log(1 > 2) // false
console.log(1 > NaN) // 遇到NaN就是false
console.log('hello' > 'hey' ) // 依次按照字符编码来比较(l < y),返回false
console.log(1 > 'hello') // 'hello'转不了数字就转成了NaN,故是false
console.log(2 >'1') // 变成2 > 1,返回true
console.log(1 > null) // null转成0,结果是true
console.log(null > null) // false
console.log(null >= undefined) // 因为在和undefined比较,故为false
console.log(null <= undefined)// false
console.log(null >= 0) // true
console.log(null == 0) //false 因为null只==undefined
console.log(1 > false) // false转成0,故true
console.log(NaN >= NaN) // false
console.log('hello' < false) // false
// 字符串和布尔值之间的比较,字符串会被转换为数字。
// 字符串会尝试被解析成数字,如果可以解析成有效的数字,则会进行比较;
// 否则,字符串会被转换为 NaN

相等操作符

字符 说明
== 相等
!= 不等
=== 全等
!== 全不等
  • == !=不会比较类型,如果类型不一致,会先进行隐式类型转换再进行比较
  • === !==是严格相等,会先比较类型是否相同,如果类型不同直接false ,类型相同再比较值是否相同
  1. NaN不等于任何类型的数值,包括自己本身,所以都返回false ;
  2. 如果都是String类型的话,比较字符编码值,如果完全一致,则返回true,否则返回false;
  3. 如果两侧都是Number类型数值,比较值是否相同;
  4. 如果两边都是Object类型,则比较地址是否一致;
  5. null == undefined 返回true
  6. 如果一侧是String,一侧是Number,将String转换为NaN之后,进行比较(如果String是数值类型则将String转换为Number进行比较)
  7. 如果一侧是Boolean,则将布尔值转换为Number类型后,再根据上述规则进行比较;
1
2
3
4
5
6
7
8
9
10
console.log(null == undefined) // true
console.log(null == null) // true
console.log(undefined == undefined) // true
console.log(1 == '1') // true
console.log(null == NaN) // false
console.log(null === undefined) // false
console.log(null === null) // true
console.log(undefined === undefined) // true
console.log(1 === '1') // false
console.log(null === NaN) // false

注意:全等===有个缺陷: NaN === NaN的结果是false ,可以用Object.is()

  • Object.is(NaN, NaN)结果是true
  • Object.is(0, -0)结果是false

赋值运算符

  • =:普通赋值运算符
  • +=:加法赋值运算符
  • -=:减法赋值运算符
  • *=:除法赋值运算符
  • /=:乘法赋值运算符
  • %=:取模赋值运算符
  • **=:指数赋值运算符
  • <<=:左移赋值运算符
  • >>=:右移赋值运算符
  • >>>=无符号右移赋值运算符,将左侧的变量向右移动右侧的值所指定的位数,且用 0 填充左侧的空位,并将结果赋给左侧的变量。
  • &&=:与赋值运算符,如果左侧的操作数为 true,则将右侧的值赋给左侧的变量;否则将 false 赋给左侧的变量。
  • ||=:或赋值运算符,如果左侧的操作数为 false,则将右侧的值赋给左侧的变量;否则将 true 赋给左侧的变量。
  • ??=:空值合并赋值运算符,x ??= y 等同于 x ?? (x = y)只有运算符左侧的值为 nullundefined 时 才会继续右侧的运算