重学JavaScript(4)

55 阅读8分钟

这是我参与「掘金日新计划 · 8 月更文挑战」的第14天

一元操作符

只有一个值的操作符叫一元操作符

递增/递减操作符

// 前缀递增
let num = 1;
++num;
// 30
// 等价于:num = num + 1

// 前缀递减
let age = 30;
--age;
// 29,等价于age = age - 1

// 后缀递增
let num1 = 1;
num1--
// 1
// num++
// 2

前缀版和后缀版的区别在于:前缀版发生在语句被求值前,后缀版发生在语句被求值后。不过,这些在等式求值的场景下才会有区别,上述代码场景中没啥区别

let a = 2;
let b = 20;
let c = ++a + b; // 23, a = 3
let d = --a + b; // 22, a = 2
let e = a + b; // 22, a = 2
let num1 = 2;
let num2 = 20;
let num3 = num1-- + num2; // 22, num1 = 1
let num4 = num1 + num2; // 21, num1 = 1
let num5 = num1++ + num2; // 21, num1 = 2

递增和递减的前缀版和后缀版可以作用于任何值,整数、字符串、布尔值、浮点值、对象等。递增和递减操作符遵循以下规则:

  • 对于字符串,如果是有效的数值形式,则转换为数值再应用改变,变量类型从字符串变为数值
  • 对于字符串,如果不是有效的数值形式,则将变量的值设置为NaN,变量类型从字符串变为数值
  • 对于布尔值,如果是false,则转为0再应用改变,类型从布尔值变为数值
  • 对于布尔值,如果是true,则转为1再应用改变,类型从布尔值变为数值
  • 对于浮点数,加1或减1
  • 如果是对象,则调用其valueOf()方法取得可以操作的值,对得到的值应用上述规则,如果是NaN,则调用toString()并再次应用其他规则,变量类型从对象变成数值
let s1 = "2";  
let s2 = "z";    
let b = false;   
let f = 1.1;    
let o = {      
    valueOf() {       
        return -1;      
    }
};
s1++;   // 值变成数值3  
s2++;   // 值变成NaN
b++;    // 值变成数值1 
f--;    // 值变成0.10000000000000009(因为浮点数不精确)  
o--;    // 值变成-2

一元加减

由一个加号表示,放在变量前,对数值没有任何影响

    let num = 25;    
    num = +num;    
    console.log(num); // 25
    
    let num1 = 25;
    num1 = -num1;
    console.log(num1); // -25,一元减号将数字变为负数

应用到非数值,则会执行与使用Number()转型函数一样的类型转换:布尔值转换为0/1,字符串根据特殊规则进行解析,对象调用valueOf()和/或toString()方法得到可以转换的值

布尔操作符

逻辑非(!)

  • 如果操作数是对象,则返回false
  • 如果操作数是空字符串,则返回true
  • 如果操作数是非空字符串,则返回false
  • 如果操作数是数字0,则返回true
  • 如果操作数是非0数值(包括infinity),则返回false
  • 如果操作数是null,则返回true
  • 如果操作数是NaN,则返回true
  • 如果操作数是undefined,则返回true

同时使用两个!!,相当于调用了转型函数Boolean(),无论操作什么类型,第一个!总会返回布尔值,第二!对布尔值取反,从而给出变量真正对应的布尔值,结果和使用Boolean()是一样的

逻辑与(&&)

true && true => true
true && false => false
false && true => false
false && false => false

如果有操作数不是布尔值,则逻辑与并不一定返回布尔值:

  • 如果第一个操作数是对象,则返回第二个操作数
  • 如果第二个操作数是对象,则只有第一个操作数求值为true才会返回该对象
  • 如果两个操作数都是对象,则返回第二个操作数
  • 如果有一个操作数是null,则返回null
  • 如果有一个操作数是NaN,则返回NaN
  • 如果有一个操作数是undefined,则返回undefined

逻辑与是一种短路操作符,即如果第一个操作数决定了结果,则永远不会对第二个操作数求值。对逻辑与操作符来说,如果第一个操作数是false,那么第二个操作数无论是什么值,结果都不会等于true

逻辑或(||)

true && true => true
true && false => true
false && true => true
false && false => false

如果有一个操作数不是布尔值,那么逻辑与操作符不一定返回布尔值:

  • 如果第一个操作数是对象,则返回第一个操作数
  • 如果第一个操作数求值为false,则返回第二个操作符
  • 如果两个操作数都是对象,则返回第一个操作数
  • 如果有一个操作数是null,则返回null
  • 如果有一个操作数是NaN,则返回NaN
  • 如果有一个操作数是undefined,则返回undefined

短路特性:第一个操作数求值为true,第二个操作数则不会被求值

乘法操作符(*)

两个数相乘。

  • 如果操作数都是数值,则执行常规的乘法运算,如果值很大不能表示,则返回Infinity或-Infinity
  • 如果有任一操作数是NaN,则返回NaN
  • 如果是Infinity乘以非0的有限数值,则根据第二个操作数的符号返回Infinity或-Infinity
  • 如果是Infinity乘以Infinity,则返回Infinity
  • 如果有不是数值的操作数,则先在后台用Number()将其转换为数值,然后再应用上述规则

除法操作符(/)

  • 如果操作数都是数值,则执行常规的除法运算,即两个正值相除是正值,两个负值相除也是正值,符号不同的值相除得到负值。如果ECMAScript不能表示商,则返回Infinity或-Infinity。
  • 如果有任一操作数是NaN,则返回NaN。
  • 如果是Infinity除以Infinity,则返回NaN。
  • 如果是0除以0,则返回NaN。
  • 如果是非0的有限值除以0,则根据第一个操作数的符号返回Infinity或-Infinity。
  • 如果是Infinity除以任何数值,则根据第二个操作数的符号返回Infinity或-Infinity。
  • 如果有不是数值的操作数,则先在后台用Number()函数将其转换为数值,然后再应用上述规则。

取余%

  • 如果操作数是数值,则执行常规除法运算,返回余数。
  • 如果被除数是无限值,除数是有限值,则返回NaN。
  • 如果被除数是有限值,除数是0,则返回NaN。
  • 如果是Infinity除以Infinity,则返回NaN。
  • 如果被除数是有限值,除数是无限值,则返回被除数。
  • 如果被除数是0,除数不是0,则返回0。
  • 如果有不是数值的操作数,则先在后台用Number()函数将其转换为数值,然后再应用上述规则

指数操作符

原本是使用Math.pow(),在ECMAScript 7中新增了 ** 来表示。另外还有支付赋值操作符 **=

let a = 3;
a ** = 2; // 9

let b = 16;
b ** = 0.5; // 4

加号 +

主要是求和。

  • 如果有任一操作数是NaN,则返回NaN;
  • 如果是Infinity加Infinity,则返回Infinity;
  • 如果是-Infinity加-Infinity,则返回-Infinity;
  • 如果是Infinity加-Infinity,则返回NaN;
  • 如果是+0加+0,则返回+0;
  • 如果是-0加+0,则返回+0;
  • 如果是-0加-0,则返回-0。

如果有一个操作数是字符串,则+变成连接符。

如果有任一操作数是对象、数值或布尔值,则调用它们的toString()方法以获取字符串,然后再应用前面的关于字符串的规则。对于undefined和null,则调用String()函数,分别获取"undefined"和"null"

减号 -

  • 如果两个操作数都是数值,则执行数学减法运算并返回结果。
  • 如果有任一操作数是NaN,则返回NaN。
  • 如果是Infinity减Infinity,则返回NaN。
  • 如果是-Infinity减-Infinity,则返回NaN。
  • 如果是Infinity减-Infinity,则返回Infinity。
  • 如果是-Infinity减Infinity,则返回-Infinity。
  • 如果是+0减+0,则返回+0。
  • 如果是+0减-0,则返回-0。
  • 如果是-0减-0,则返回+0。
  • 如果有任一操作数是字符串、布尔值、null或undefined,则先在后台使用Number()将其转换为数值,然后再根据前面的规则执行数学运算。如果转换结果是NaN,则减法计算的结果是NaN。
  • 如果有任一操作数是对象,则调用其valueOf()方法取得表示它的数值。如果该值是NaN,则减法计算的结果是NaN。如果对象没有valueOf()方法,则调用其toString()方法,然后再将得到的字符串转换为数值。

关系符

关系操作符执行比较两个值的操作,包括小于(<)、大于(>)、小于等于(<=)和大于等于(>=),用法跟数学课上学的一样,这几个操作符都返回布尔值。

  • 如果操作数都是数值,则执行数值比较。
  • 如果操作数都是字符串,则逐个比较字符串中对应字符的编码。
  • 如果有任一操作数是数值,则将另一个操作数转换为数值,执行数值比较。
  • 如果有任一操作数是对象,则调用其valueOf()方法,取得结果后再根据前面的规则执行比较。如果没有valueOf()操作符,则调用toString()方法,取得结果后再根据前面的规则执行比较。
  • 如果有任一操作数是布尔值,则将其转换为数值再执行比较