0. 检测类型操作符

0.1 typeof

多用于基本类型检测,返回值有 stringnumberbooleanundefinedobjectfunction

  • 检测 null 会返回 object

  • 检测函数时会返回 function

0.2 instanceof

用于检测对象类型

  1. result = variable instanceof constructor;
  • 所有引用类型的值都是 Object 的实例,在检测引用类型值和 Object 构造函数时,instanceof 操作符始终返回 true

  • 使用 instanceof 操作符检测基本类型的值时,始终返回 false

1. 算术操作符

1.1 递增、递减

分为前置和后置

  • 前置放在变量之前,表示先对变量加减 1 后再进行变量的其他操作

  • 后置放在变量之后,表示一条语句结束后再对变量加减 1

对任何值都适用,包括字符串、布尔值、浮点数值和对象

  • 包含有效数字字符的字符串时,先将其转换为数值,在执行加减 1 操作,字符串变量变成数值变量

  • 不包含有效数字字符时,将变量的值设置为 NaN,字符串变量变成数值变量

  • 布尔值,false 变换成 0true 变换成 1,再进行加减 1 操作,布尔值变成数值变量

  • 浮点数值,直接进行加减 1 操作

  • 对象,先调用对象的 valueOf() 方法以取得一个可供操作的值,应用前面的规则,如果结果为 NaN,再调用对象的 toString() 方法后再应用前面的规则。对象变量变成数值变量

注意:n++ 和 n = n + 1 一样吗? 当 n 是数字或其它类型的时候,是一样的 而当 n 是字符串时,一个依然是数学运算,另一个却是字符串拼接

  1. var n = '10'
  2. n = n + 1; //=> n: '101'
  3. n++ //=> n: 11

1.2 一元加减

在对非数值应用一元加或减操作符时,会像 Number() 转型函数一样执行转换

  1. var s = "01";
  2. s = +s; //s=1;
  3. {} + 'aa' //=> NaN,原因在于 {} 会被解析为代码块,后面就只是 + 'aa',就是一元加
  4. ({}) + 'aa' //=> '[object Object]aa',这时就是字符串拼接

一元减主要用于表示负数

2. 位操作符

位操作符应用于最基本的层次上,按内存中表示数值的位来操作数值,同样效果中,速度更快

  • 所有数值以 IEEE-754 64 位格式存储

  • 默认情况下,所有的整数都是有符号整数

  • 当数值应用位操作符时

    • 64 位数值被转换成 32 位数值

    • 执行位操作

    • 32 位数值转换为 64 位数值

    • 副效应:对特殊的 NaNInfinity 值应用位操作时,会被当 0 处理

  • 对非数值应用位操作

    • 自动使用 Number() 函数转换为数值,然后应用位操作

注意:在内存中,负数是以二进制补码的格式存储的,但是在将负数以二进制字符串形式输出时,我们看到的是负数的绝对值的二进制码前面加一个负号,而不是以补码形式展现。

2.1 按位非 ~

返回数值的反码,本质是操作数是负值减 1

2.2 按位与 &

两个数值的每一位对齐,对应位都是 1 时才返回 1,任何一位是 0,结果都是 0

2.3 按位或 |

两个数值的每一位对齐,对应位有一个是 1 就返回 1,都是 0 时返回 0

2.4 按位异或 ^

两个数值的每一位对齐,对应位只有一个 1 时才返回 1,都是 1 或都是 0,则返回 0

2.5 左移 <<

将数值的所有位向左移动指定位数

  • 0 来填充空位,以便得到完整的 32 位二进制数

  • 左移不会影响到符号位

2.6 有符号右移 >>

将数值向右移动指定位数

  • 保留符号位

  • 用符号位的数来填充所有空位,以便得到完整的值

2.7 无符号右移 >>>

  • 0 来填充空位

  • 对正数的有符号右移和无符号右移是一样的

  • 对负数进行无符号右移会把负数的二进制码当成正数的二进制码,导致结果非常之大

3. 布尔操作符

3.1 逻辑非 !

应用于任何值,先将操作数转换成布尔值,再对其求反

规则:实际上先对操作数应用 Boolean() 转换为布尔值,然后再取反

同时使用两个逻辑非操作符,实际上就会模拟 Boolean() 函数的行为,用于将一个值转换为与其对应的布尔值

3.2 逻辑与 &&

可以应用于各种类型的操作数,而不仅仅是布尔值

在有一个操作数不是布尔值时,就不一定返回布尔值了

规则:

  • 第一个操作数不是布尔值,则使用 Boolean() 进行转换,是布尔值,则直接判断

  • 结果为 true,则返回第二个操作数

  • 结果是 false,则返回第一个操作数。

    • 如果第一个操作数是 false,返回 false

    • 如果第一个操作数是 null,返回 null

    • 如果第一个操作数是 NaN,返回 NaN

    • 如果第一个操作数是 undefined,返回 undefined

    • 如果第一个操作数是 '',返回 ''

    • 如果第一个操作数是 0,返回 0

短路操作:如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值

  1. var found = true;
  2. var result = (found && someUndefined);//发生错误
  3. alert(result);//这一行不会执行
  4. var found = false;
  5. var result = (found && someUndefined);//不会发生错误
  6. alert(result);//执行结果 false

回调函数:传值是函数时,让函数执行

  1. function fn(callback) {
  2. //=> 如果传递的值是一个函数,我们让其执行
  3. // if(typeod callback === 'function') {
  4. // callback()
  5. // }
  6. callback && callback(); //=> 如果 callback 存在则执行它
  7. //=> 这种写法是不够严谨的,但是经常使用。因为约定好,默认 callback 要不然就传函数,要不然就不传。
  8. }
  9. fn(function() {})

3.3 逻辑或 ||

规则:

  • 第一个操作数不是布尔值,则使用 Boolean() 进行转换,是布尔值,则直接判断

  • 结果为 true,则返回第一个操作数

  • 结果是 false,则返回第二个操作数

短路操作:如果第一个操作数的求值结果为 true,那么就不会再对第二个操作数求值

赋值语句经常采用这种模式:用以给参数赋默认值

  1. var myObject = preferredObject || backupObject;

虽然不够严谨,但是在真实项目中约定俗称,经常使用。因为默认要么不传值,要么传递的就是所需要的值。所以在需要传递的值为假的时候,应该避免这种默认值定义方式

4. 乘性操作符

在操作数为非数值的时候会执行自动类型转换,先使用 Number() 转型函数将其转换为数值

4.1 乘法 *

规则:

  • 乘积超过数值的表示范围,则返回 Infinity-Infinity

  • 有一个操作数是 NaN,则结果为 NaN

  • Infinity0 相乘,结果为 NaN

  • Infinity 与非 0 数值相乘,结果为 Infinity-Infinity

  • InfinityInfinity 相乘,结果为 Infinity

  • 操作数不是数值,则在后台调用 Number() 将其转换为数值,再应用上面的规则

4.2 除法 /

规则:

  • 商超过数值的表示范围,则返回 Infinity-Infinity

  • 有一个操作数是 NaN,则结果为 NaN

  • InfinityInfinity 除,结果为 NaN

  • 0 的有限数被 0 除,结果是 Infinity-Infinity

  • Infinity 被任何数值除,结果是 Infinity-Infinity

  • 操作数不是数值,则在后台调用 Number() 将其转换为数值,再应用上面的规则

4.3 求模 %

求余数

规则:

  • 都是数值,执行常规除法,返回除得的余数

  • 被除数是 Infinity,除数是有限数值,结果返回 NaN

  • 被除数是有限数值,除数是 0,结果是 NaN

  • InfinityInfinity 除,结果是 NaN

  • 被除数是有限大的数值,除数是 Infinity,结果是被除数

  • 被除数是 0,结果是 0

  • 操作数不是数值,则在后台调用 Number() 将其转换为数值,再应用上面的规则

4.4 幂 **

幂运算符返回第一个操作数做底数,第二个操作数做指数的乘方。即 $ var1^{var2} $,其中 var1 和 var2 是其两个操作数。

幂运算符是右结合的。a ** b ** c 等同于 a ** (b ** c)

包括 PHP 或 Python 等的大多数语言中,都包含幂运算符(一般来说符号是 ^ 或者 **)。这些语言中的幂运算符有着比其他的单目运算符(如一元 + 或一元 - )更高的优先级。但是作为例外,在 Bash 中,** 运算符被设计为比单目运算符优先级更低。在最新的 JavaScript(ES2016) 中,禁止使用带歧义的幂运算表达式。比如,底数前不能紧跟一元运算符(+/-/~/!/delete/void/typeof

  1. -2 ** 2;
  2. // 在 Bash 中等于 4 ,而在其他语言中一般等于 -4
  3. // 在 JavaScript 中是错误的,因为这会有歧义
  4. -(2 ** 2);
  5. // -4 在JavaScript中能够明显体现出作者的意图

示例

  1. 2 ** 3 // 8
  2. 3 ** 2 // 9
  3. 3 ** 2.5 // 15.588457268119896
  4. 10 ** -1 // 0.1
  5. NaN ** 2 // NaN
  6. 2 ** 3 ** 2 // 512
  7. 2 ** (3 ** 2) // 512
  8. (2 ** 3) ** 2 // 64

如果要反转求幂表达式结果的符号,你可以采用这样的方式:

  1. -(2 ** 2) // -4

强制求幂表达式的基数为负数:

  1. (-2) ** 2 // 4

5. 加性操作符

5.1 加法 +

规则:

  • 操作数是 NaN,返回 NaN

  • InfinityInfinity,结果是 Infinity

  • -Infinity-Infinity,结果是 -Infinity

  • Infinity-Infinity,结果 NaN

  • 操作数是字符串

    • 都是字符串,进行拼接

    • 只有一个是字符串,另一个转换为字符串,进行拼接

    • 操作数是对象、数值、布尔值,调用 toString() 方法取得相应的字符串值

    • 操作数是 undefinednull,调用 String() 函数取得字符串值

5.2 减法 -

规则:

  • 操作数是 NaN,返回 NaN

  • InfinityInfinity,结果是 NaN

  • -Infinity-Infinity,结果是 NaN

  • Infinity-Infinity,结果 Infinity

  • -InfinityInfinity,结果 -Infinity

  • 操作数是字符串、布尔值、nullundefined,先在后台调用 Number() 函数转换为数值,在按上面规则执行

  • 操作数是对象,调用对象的 valueOf() 方法取得对象的数值,如果结果是 NaN,则减法的结果是 NaN。如果没有 valueOf() 方法,则调用其 toString() 方法将其得到的字符串转换为数值

6. 关系操作符

关系操作符有:<、>、<=、>=

规则:

  • 两个数都是数值,则执行数值的比较

  • 都是字符串,比较两个字符串对应的字符编码值

  • 一个是数值,则将另一个也转换为数值,执行比较

  • 一个是对象,调用对象的 valueOf() 方法取得对象的数值,如果没有 valueOf() 方法,则调用其 toString() 方法将其得到的字符串转换为数值

  • 布尔值,将其转换为数值执行比较

  • 操作数存在 NaN 或者 undefinednull,结果都是 false

7. 相等操作符

7.1 相等与不相等 ==

规则:

  • 先转换后比较

  • 布尔值,转换为数值再比较

  • 一个字符串,一个数值,则将字符串转换为数值再比较

  • 都是字符串,比较两个字符串对应的字符编码值

  • 一个是对象,另一个是字符串,则将对象转换为字符串再比较

  • 都是对象,则比较是不是同一对象,如果指向同一对象,则相等返回 true

  • 其他都是转换为数值再比较

  • nullundefined 是相等的

  • NaN ,使用相等结果都是 false ,使用不相等结果都是 trueNaN 不等于任何值,包括自身

  1. 1==true //=> true
  2. 1==false //=> false
  3. 2==true //=> false
  4. [] == 0 //=> true,都转换为数字
  5. [] == '0' //=> false,左边转换为字符串 '',再比较
  6. {} == '[object Object]' //=> true,左边先转换为字符串,再比较
  7. []==false //=> true,都转换为数字
  8. []==true //=> false,都转换为数字
  9. ![]==false //=> true,先算 ![] 为 false,再比较
  10. ![]==true //=> false,先算 ![] 为 false,再比较

7.2 全等和不全等 ===

只在两个操作数未经转换就相等的情况下才返回 true,也就是类型和值都要相等。真实项目中为了保证代码的严谨性,应该更多的使用严格相等。

8. 条件、赋值、逗号

8.1 条件操作符 ? :

  1. variable = boolean_expression ? true_value : false_value

可以执行多条语句,用小括号包裹,不同语句用逗号隔开;也可以不执行任何语句,用 null undefined等占位

  1. var num = 12;
  2. num > 10 ? (num++, num*=10) : null;

8.2 赋值操作符 =

简单的赋值操作符由等号表示,如果在等号前面再添加乘性操作符、加性操作符或位操作符,就变成了复合操作符。

  • *=

  • /=

  • %=

  • +=

  • -=

  • <<=

  • =

  • =

设计这些操作符的主要目的是简化赋值操作,使用它们不会带来任何性能的提升。

8.2 逗号操作符,

使用逗号操作符可以在一条语句中执行多个操作

  1. var num = 1, num2 = 2, num3 = 3;

多用于声明多个变量,但除此之外,还可以用于赋值,在用于赋值时,逗号操作符总会返回表达式中的最后一项。

  1. var num = (5, 1, 4, 0); //=> num: 0

在三元运算符中,也可以使用逗号来分隔多条语句