ES6 前,JavaScript 共有五种原始数据类型:Undefined、Null、Boolean、Number、String
先由一道传说的大厂面试题开始
如何让 (a==1&&a==2&a==3) 为true?
答案基本上都如下:
let a = {
i:1,
valueOf(){
return a.i++
},
toString: function() {
return a.i++
}
}
console.log(a==1&&a==2&a==3);//true
这里就涉及:
- 隐式转换
- Object的valueOf函数,toString函数
object隐式转换规则
根据 ES5 9.8 的规范
object在发生到number和string的转换规则如下:
| 参数类型 | 设备文件名 |
|---|---|
| Object |
1. primValue = ToPrimitive(input, String/Number)
2. 返回ToString(primValue). |
让我们看规范 9.1,函数语法表示如下:
ToPrimitive(input[, PreferredType])
第一个参数是 input,表示要处理的输入值。
第二个参数是 PreferredType,非必填,表示希望转换成的类型,有两个值可以选,Number 或者 String。
当不传入 PreferredType 时,如果 input 是日期类型,相当于传入 String,否则,都相当于传入 Number。
如果传入的 input 是 Undefined、Null、Boolean、Number、String 类型,直接返回该值。
接下来:
如果是 ToPrimitive(obj, Number),处理步骤如下:
-
如果 obj 为 基本类型,直接返回
-
否则,调用 valueOf 方法,如果返回一个原始值,则 JavaScript 将其返回。
-
否则,调用 toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
-
否则,JavaScript 抛出一个类型错误异常。
如果是 ToPrimitive(obj, String),处理步骤如下:
-
如果 obj为 基本类型,直接返回
-
否则,调用 toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
-
否则,调用 valueOf 方法,如果返回一个原始值,则 JavaScript 将其返回。
-
否则,JavaScript 抛出一个类型错误异常。
扩展:当是==== 的时候
利用Object.defineProperty,实现的方法如下:
let value = 1;
Object.defineProperty(window,'a',{
get(){
return value++
}
})
其他操作符
当执行 + 运算的时候,会执行怎样的步骤呢?根据规范11.6.1 来捋一捋:
当计算 value1 + value2时:
-
lprim = ToPrimitive(value1)
-
rprim = ToPrimitive(value2)
-
如果 lprim 是字符串或者 rprim 是字符串,那么返回 ToString(lprim) 和 ToString(rprim)的拼接结果
-
返回 ToNumber(lprim) 和 ToNumber(rprim)的运算结果
console.log(null + 1);
按照规范的步骤进行分析:
-
lprim = ToPrimitive(null) 因为null是基本类型,直接返回,所以 lprim = null
-
rprim = ToPrimitive(1) 因为 1 是基本类型,直接返回,所以 rprim = null
-
lprim 和 rprim 都不是字符串
-
返回 ToNumber(null) 和 ToNumber(1) 的运算结果
接下来:
ToNumber(null) 的结果为0,ToNumber(1) 的结果为 1
所以,null + 1 相当于 0 + 1,最终的结果为数字 1。
对象与数组
console.log([] + {});
按照规范:
-
lprim = ToPrimitive([]),lprim = ""
-
rprim = ToPrimitive({}),相当于调用 ToPrimitive({}, Number),先调用 valueOf 方法,返回对象本身,因为不是原始值,调用 3. toString 方法,返回 "[object Object]"
-
lprim 和 rprim 都是字符串,执行拼接操作
所以,[] + {} 相当于 "" + "[object Object]",最终的结果是 "[object Object]"。
== 相等
"==" 用于比较两个值是否相等,当要比较的两个值类型不一样的时候,就会发生类型的转换。
关于使用"=="进行比较的时候,具体步骤可以查看规范11.9.5:
当执行x == y 时:
1.如果x与y是同一类型:
x是Undefined,返回true
x是Null,返回true
x是数字:
x是NaN,返回false
y是NaN,返回false
x与y相等,返回true
x是+0,y是-0,返回true
x是-0,y是+0,返回true
返回false
x是字符串,完全相等返回true,否则返回false
x是布尔值,x和y都是true或者false,返回true,否则返回false
x和y指向同一个对象,返回true,否则返回false
2. x是null并且y是undefined,返回true 3. x是undefined并且y是null,返回true
-
x是数字,y是字符串,判断x == ToNumber(y)
-
x是字符串,y是数字,判断ToNumber(x) == y
-
x是布尔值,判断ToNumber(x) == y
-
y是布尔值,判断x ==ToNumber(y)
-
x不是字符串或者数字,y是对象,判断x == ToPrimitive(y)
-
x是对象,y不是字符串或者数字,判断ToPrimitive(x) == y
-
返回false
最后放上:
参考大佬文章:JavaScript深入之头疼的类型转换