# 数据类型隐式转换规律
- 原始基础类型:Undefined、 Null、 String、 Number、 Boolean、 Symbol、Object、bigInt
- JS内置对象:Date, Array, Math, Number, Boolean, String, Array, RegExp, Function, Error。
- 隐式中涉及的三种转换:
对象转换为原始值 ,ToPrimitive(input, PreferredType)
- PreferredType被标记为Number
- 如果输入值是原始值 ,则直接返回
- 否则如果输入的值是一个对象,则调用对象的valueOf()方法;如果valueof()返回的是一个原始值,则返回这个原始值。
- 否则调用对象toString()方法,如果返回的是一个原始值,则返回原始值;否则抛出TypeError异常
- PreferredType被标记为String
- 如果输入值是原始值 ,则直接返回
- 否则调用对象的toString()方法;如果toString()返回的是一个原始值,则返回这个原始值。
- 否则输入的值是一个对象,则调用该对象的valueOf(),如果返回的是一个原始值,则返回原始值;否则抛出TypeError异常
- 无参数PreferredType时
- 该对象为Date类型,则PreferredType被设置为String
- 否则PreferredType被设置为Number
值转换为数字,ToNumber()
| 参数 | 结果 |
|---|---|
| undefined | NaN |
| null | +0 |
| 布尔值 | true转换1,false转换为+0 |
| 数字 | 无须转换 |
| 字符串 | 有字符串解析为数字,例如:‘324’转换为324,‘qwer’转换为NaN |
| 对象(obj) | 先进行 ToPrimitive(obj, Number)转换得到原始值,在进行ToNumber转换为数字 |
- 值转换为字符串,ToString()
| 参数 | 结果 |
|---|---|
| undefined | 'undefined' |
| null | 'null' |
| 布尔值 | 转换为'true' 或 'false' |
| 数字 | 数字转换字符串,比如:1.765转为'1.765' |
| 字符串 | 无须转换 |
| 对象(obj) | 先进行 ToPrimitive(obj, String)转换得到原始值,在进行ToString转换为字符串 |
- valueOf()与toString()是Object.prototype上的属性,故所有对象都拥有。
- Number, Boolean, String这三种构造函数生成基础值的对象形式
let num = new Number('123');
num.valueOf(); // 123
var str = new String('12df');
str.valueOf(); // '12df'
var bool = new Boolean('fd');
bool.valueOf(); // true
2
3
4
5
6
7
- Date特殊对象
var a = new Date();
a.valueOf(); // 1515143895500
2
- 除此之外返回的都是this,即对象本身
var a = new Array();
a.valueOf() === a; // true
var b = new Object({});
b.valueOf() === b; // true
2
3
4
5
- toString()方法
- Number、Boolean、String、Array、Date、RegExp、Function这几种构造函数生成的对象,通过toString转换后会变成相应的字符串的形式,因为这些构造函数上封装了自己的toString方法。如:
Number.prototype.hasOwnProperty('toString'); // true
Boolean.prototype.hasOwnProperty('toString'); // true
String.prototype.hasOwnProperty('toString'); // true
Array.prototype.hasOwnProperty('toString'); // true
Date.prototype.hasOwnProperty('toString'); // true
RegExp.prototype.hasOwnProperty('toString'); // true
Function.prototype.hasOwnProperty('toString'); // true
var num = new Number('123sd');
num.toString(); // 'NaN'
var str = new String('12df');
str.toString(); // '12df'
var bool = new Boolean('fd');
bool.toString(); // 'true'
var arr = new Array(1,2);
arr.toString(); // '1,2'
var d = new Date();
d.toString(); // "Wed Oct 11 2017 08:00:00 GMT+0800 (中国标准时间)"
var func = function () {}
func.toString(); // "function () {}"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 除这些对象及其实例化对象之外,其他对象返回的都是该对象的类型,(有问题欢迎告知),都是继承的Object.prototype.toString方法。
var obj = new Object({});
obj.toString(); // "[object Object]"
Math.toString(); // "[object Math]"
2
3
4
WARNING
故:从valueOf()与toString()函数对对象的转换可知,对于ToPrimitive(input, preferredType),preferredType没有设定时,除Date被设置为String类型外,其他会被设置为Number;
因为valueOf将Number、String、Boolean基础类型的对象类型转换为基础类型,Data转换为毫秒数,其他返回为对象本身;而toString会将所有对象转换为字符串,显然valueOf转换更合理些
因此先将PreferredType设置为Number类型,进行valueOf转换;而Date类型的对象,没有设定PreferredType时,默认设置为String
算术运算中的隐私转换
({} + {}) = ? 两个对象的值进行+运算符,肯定要先进行隐式转换为原始类型才能进行计算。 1、进行ToPrimitive转换,由于没有指定
PreferredType类型,{}会使默认值为Number,进行ToPrimitive(input, Number)运算。 2、所以会执行valueOf方法,({}).valueOf(),返回的还是{}对象,不是原始值。 3、继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。 故得到最终的结果,"[object Object]" + "[object Object]" = "[object Object][object Object]"2 * {} = ? 1、首先*运算符只能对number类型进行运算,故第一步就是对{}进行
ToNumber类型转换。 2、由于{}是对象类型,故先进行原始类型转换,ToPrimitive(input, Number)运算。 3、所以会执行valueOf方法,({}).valueOf(),返回的还是{}对象,不是原始值。 4、继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。 5、转换为原始值后再进行ToNumber运算,"[object Object]"就转换为NaN。 故最终的结果为2 * NaN = NaN比较运算隐式转换---不同类型的简单类型比较时,先想 Number 转,再向 String 类型
比较运算 x==y, 其中 x 和 y 是值,返回 true 或者 false。这样的比较按如下方式进行:
- 若 Type(x) 与 Type(y) 类型相同, 则
- 若 Type(x) 与 Type(y)为 Undefined, 返回 true。
- 若 Type(x) 与 Type(y)为 Null, 返回 true。
- 若 Type(x) 与 Type(y)为 Number, 则
- 若 x 为 NaN, 返回 false。
- 若 y 为 NaN, 返回 false。
- 若 x 与 y 为相等数值, 返回 true。
- 若 x 为 +0 且 y 为 −0, 返回 true。
- 若 x 为 −0 且 y 为 +0, 返回 true。
- 返回 false。
- 若 Type(x) 与 Type(y) 为 String, 则当 x 和 y 为完全相同的字符序列(长度相等且相同字符在相同位置)时返回 true。 否则, 返回 false。
- 若 Type(x) 与 Type(y) 为 Boolean, 当 x 和 y 为同为 true 或者同为 false 时返回 true。 否则, 返回 false。
- 当 x 和 y 为引用同一对象时返回 true。否则,返回 false。
- 若 x 为 null 且 y 为 undefined, 返回 true。
- 若 x 为 undefined 且 y 为 null, 返回 true。
- 若 Type(x) 为
Number且 Type(y) 为String,返回比较 x == ToNumber(y) 的结果。 - 若 Type(x) 为
String且 Type(y) 为Number,返回比较 ToNumber(x) == y 的结果。 - 若 Type(x) 为
Boolean, 返回比较 ToNumber(x) == y 的结果。 - 若 Type(y) 为
Boolean, 返回比较 x == ToNumber(y) 的结果。 - 若 Type(x) 为
String 或 Number,且 Type(y) 为Object,返回比较 x == ToPrimitive(y) 的结果。 - 若 Type(x) 为
Object且 Type(y) 为String 或 Number, 返回比较 ToPrimitive(x) == y 的结果。 - 返回 false。
- 若 Type(x) 与 Type(y) 类型相同, 则
TIP
- x、y类型相同时:
- Number类型时,NaN与NaN不相待
- 对象时,需要是引用同一个对象
- 和类型不相同时:
- x,y 为null、undefined两者中一个则相等
- x、y为Number和String类型时,则转换为Number类型比较。
- 有Boolean类型时,Boolean转化为Number类型比较。
- 一个Object类型,一个String或Number类型,将Object类型进行原始转换后,按上面流程进行原始值比较。
- 重写 valueOf 与 toString 方法的例子
var a = {
valueOf: function () {
return 1;
},
toString: function () {
return '123'
}
}
true == a // true;
2
3
4
5
6
7
8
9
首先,x与y类型不同,x为boolean类型,则进行ToNumber转换为1,为number类型。
接着,x为number,y为object类型,对y进行原始转换,ToPrimitive(a, ?),没有指定转换类型,默认number类型。
而后,ToPrimitive(a, Number)首先调用valueOf方法,返回1,得到原始类型1。
最后 1 == 1, 返回true。
[] == !{}
- ! 运算符优先级高于==,故先进行!运算。
- !{}运算结果为false,结果变成 [] == false比较。
- 等式右边y = ToNumber(false) = 0。结果变成 [] == 0。
- 比较变成ToPrimitive([]) == 0。
- 按照上面规则进行原始值转换,[]会先调用valueOf函数,返回this。
- 不是原始值,继续调用toString方法,x = [].toString() = ''。
- 故结果为 '' == 0比较。
- 等式左边x = ToNumber('') = 0。
- 所以结果变为: 0 == 0,返回true,比较结束。
题目:a == 1 && a == 2 && a == 3 成立
- 对象类型转换步骤:
- Object 与 Number,把 Object.valueOf() 和 Object.toString()转换为基本数字类型
- 数组类型转换,通过 toString()-->Array.join()等于 shift 操作 取出第一个元素
- 对象类型转换步骤:
// 解一
var a = {
i: 1,
toString: function () {
return a.i++;
}
}
// 解二
var a = [1, 2, 3];
// 解三
var val = 0;
Object.defineProperty(window, 'a', { // 这里要window,这样的话下面才能直接使用a变量去 ==
get: function () {
return ++val;
}
});
console.log(a == 1 && a == 2 && a == 3);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 试分析该段代码
const a = {
i: 1,
toString: function () {
return a.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('hello world!');
}
2
3
4
5
6
7
8
9
10