弱类型的JS隐式转换

# 弱类型的JS隐式转换

参考文献:从++[[]][+[]]+[+[]]==10?深入浅出弱类型JS的隐式转换 (opens new window)

[TOC]

# 一、强弱类型

  • 强类型
    • 每个变量和对象都必须具有声明类型,他们是在编译的时候就确定类型的数据,在执行时类型不能更改。
  • 弱类型
    • 在执行的时候才会确定类型。
  • 强类型安全,而且效率高。弱类型相比而言不安全 ,但它让不正确的类型可以通过隐式转换得到正确类型,就好像所有运算能进行运算一样

# 二、ECMAScript 运算符优先级

运算符 描述
. [] () 字段访问、数组下标、函数调用以及表达式分组
++ -- - + ~ ! delete new typeof void 一元运算符、返回数据类型、对象创建、未定义值
* / % 乘法、除法、取模
+ - + 加法、减法、字符串连接
<< >> >>> 移位
< <= > >= instanceof 小于、小于等于、大于、大于等于、instanceof
== != === !== 等于、不等于、严格相等、非严格相等
& 按位与
^ 按位异或
&& 逻辑与
?: 条件
= oP= 赋值、运算赋值
, 多重求值

# 2.1一元运算符

一元运算符只有一个参数,即要操作的对象或值。它们是 ECMAScript 中最简单的运算符。

# 2.1.1一元 + 和一元 - 运算符

  • 将操作数转换为Number类型,其中一元-运算符还会反转其正负(如果操作符为NaN,仍为NaN。

    +true	// 1
    +false	// 0
    
    1
    2
  • 计算字符串的方式与 parseInt() 相似,主要的不同是只有对以 "0x" 开头的字符串(表示十六进制数字),一元运算符才能把它转换成十进制的值

    • 用一元加法转换 "010",得到的总是 10,而 "0xB" 将被转换成 11。

# 2.1.2++前增量运算符

数值上+1。

# 2.2+ - 运算符

# 2.2.1+ 运算符

  • 特殊行为
    • 某个运算数是 NaN,那么结果为 NaN。
    • -Infinity 加 -Infinity,结果为 -Infinity。
    • Infinity 加 -Infinity,结果为 NaN。
    • +0 加 +0,结果为 +0。
    • -0 加 +0,结果为 +0。
    • -0 加 -0,结果为 -0。
  • ECMAScripts5规范 (opens new window):如果只有一个运算数是字符串,把另一个运算数转换成字符串,结果是两个字符串连接成的字符串。
1+"1"    //"11"
"1"+1    //"11"
"1"+"1"    //"11"
1
2
3
  • 转数值:只对null、''、false、数值字符串有效。
const num1 = +null;
const num2 = +"";
const num3 = +false;
const num4 = +"169";
// num1 num2 num3 num4 => 0 0 0 169
1
2
3
4
5

# 2.2.2- 运算符

  • 特殊行为
    • 某个运算数是 NaN,那么结果为 NaN。
    • Infinity 减 Infinity,结果为 NaN。
    • -Infinity 减 -Infinity,结果为 NaN。
    • Infinity 减 -Infinity,结果为 Infinity。
    • -Infinity 减 Infinity,结果为 -Infinity。
    • +0 减 +0,结果为 +0。
    • -0 减 -0,结果为 -0。
    • +0 减 -0,结果为 +0。
    • 某个运算符不是数字,那么结果为 NaN。
  • 规范:如果有一个不是数字,会调用 ToNumber 方法按照规则转化成数字类型,然后进行相减。

# 2.3 类型转换

# 2.3.1 显式类型转换(强制类型转换)

  • Number()

  • parseInt() 可以用来去掉px

  • parseFloat()

# 2.3.2 隐式类型转换

参考教程:你所忽略的js隐式转换 (opens new window)

  1. 将值转为原始值,ToPrimitive()
  2. 将值转为数字,ToNumber()
  3. 将值转为字符串,ToString()
  • + 200 + '3' 变成字符串

  • - * / % '200' - 3 变成数字

    '1' * 1			// 1
    'a' * 1			// NaN
    null * 1		// 0 null的二进制表示都是0
    undefined * 1	// NaN
    
    1
    2
    3
    4
  • ++ -- 变成数字

  • > < 数字的比较 、字符串的比较(Object遇到> <会转换成字符串比较)

  • ! 取反 把右边的数据类型转成布尔值

let a = 3;
let b = new Number(3);

console.log(a == b);	// true
console.log(a === b);	// false
1
2
3
4
5

new Number()是一个内置的函数构造函数。 虽然它看起来像一个数字,但它并不是一个真正的数字:它有一堆额外的功能,是一个对象。

当我们使用==运算符时,==会引发隐式类型转换,右侧的对象类型会自动拆箱为Number类型,返回true

a=?
if(a==1 && a==2 && a==3){
  console.log(1)
}

// answer1
const a = {
  num1: 0,
  valueOf() {
    return this.num1 += 1
  }
};

// answer2
let a = [1,2,3]
a.toString = a.shift
// or
a.join = a.shift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2.3.2.1 布尔值转数值
# 2.3.2.2 字符串和数字,字符串转数字
# 2.3.2.3 对象,优先用valueOf(),其次toString()
# 严格比较运算符===与比较运算符==的区别
  • 对于关系运算符(比如 <=)来说,会先将操作数转为原始值,使它们类型相同,再进行比较运算。

  • == 执行类型转换的规则如下:(数字>字符串>对象)

    如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。

    如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。

    如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。

    如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。