相关文章
js基石之数据类型一:类型分类&区别
js基石之数据类型二:类型判断
js基石之数据类型三:类型转换
js基石之Number:本质
js基石之Number:应用(数字运算,数字&字符串转换,不同进制表示&相互转换)
js基石之字符: ASCII,GBK,Unicode,utf-32,utf-16,utf-8,encodeuri,encodeuricomponent,base64
js基石之Symbol值
js基石之Object,Map,WeakMap
js基石之Array,Stack,Queue,Set,WeakSet
类型转换(没错 八股本股)
原始值类型相互转换
引用类型转换为原始类型
to Boolean:
这种是最简单的 除了空对象(null) 其他任何对象都会转化为true.
to String & toNumber
对象在转换到这两个类型的时候 逻辑是相似的 只是顺序会有不同。
- 判断对象是否实现了
Symbol.toPrimitive
方法。
如果实现了则按照这个方法返回,如果对象没有实现 则走js内部的Symbol.toPrimitive
方法。
内部Symbol.toPrimitive
大概逻辑如下:
function ToPrimitive(input, preferredType) {
switch (preferredType) {
case Number:
return toNumber(input);
break;
case String:
return toString(input);
break;
default:
return toNumber(input);
}
function isPrimitive(value) {
return value !== Object(value);
}
function toString() {
if (isPrimitive(input.toString())) return input.toString();
if (isPrimitive(input.valueOf())) return input.valueOf();
throw new TypeError();
}
function toNumber() {
if (isPrimitive(input.valueOf())) return input.valueOf();
if (isPrimitive(input.toString())) return input.toString();
throw new TypeError();
}
}
- 如果是转换为number则调用ToPrimitive(input, 'Number')
- 如果是转换为String 则调用ToPrimitive(input, 'String')
- 不能转换为原始值走报错逻辑
- 可以转换为原始值 则返回当前的原始值 然后在继续运算 后续可能还会将这个原始值在进行类型转换。具体看
原始值类型相互转换
。
但是基于上面的步骤 有两个特例==
和二元+
运算符会触发默认转换模式 类似调用了ToPrimitive(input, Number)。
valueOf()和toString()都是Object.prototype上的方法 因此所有对象都有这两个方法,valueOf默认返回对象本身,toString返回对象的类型标识。
这两个方法是可以被覆盖重写的,例如Array.prototype就覆盖了toString()方法,valueOf()一般没有重写。
例子1:
const obj = {
value: 1,
[Symbol.toPrimitive](){
return 10
},
toString(){
return '20'
},
valueOf(){
return 30
}
};
obj + 1 // 11
obj + '1' // '101'
例子2:
const obj = {
value: 1,
toString(){
return '20'
},
valueOf(){
return 30
}
};
obj + 1 // 31
obj + '1' // '301'
例子3:
const obj = {
value: 1,
toString(){
return '20'
},
valueOf(){
return 30
}
};
console.log(`${obj}`) // '20'
例子4
{} + [] + {} + [1]
// 按照上面的步骤 {} =>[object Object]
// [] => '' [1]=> '1'
// 所以结果应该是:
'[object Object][object Object]1'
然而直接在浏览器打印
// 结果是 '0[object Object]1'
因为第一个{}被解析为代码块了而不是一个对象
等价于 + [] + {} + [1]
+ [] 按照原始类型进行转换 所以是0
{}转换为[object Object]
[1]转换为字符 '1'
想得到正确的结果 需要这样写({} + [] + {} + [1])
显式转换: 开发者主动调用api进行转换
to Number: Number()/parseInt()/parseFloat()
let str = "123";
let num = Number(str); // num 现在是数字 123
let str = "123.45";
let num1 = parseInt(str); // num1 现在是数字 123
let num2 = parseFloat(str); // num2 现在是数字 123.45
to String: String()/ toString()
let num = 123;
let str = String(num); // str 现在是字符串 "123"
let num = 123;
let str = num.toString(); // str 现在是字符串 "123"
to Boolean: Boolean()
let str = "hello";
let bool = Boolean(str); // bool 现在是布尔值 true
隐式转换:js引擎在运算过程中进行的转换
to Number
- 使用一元
+
运算符:
let str = "123";
let num = +str; // num 现在是数字 123
- 在数学运算中,非数字类型会被自动转换为数字:
let str = "123";
let num = str * 1; // num 现在是数字 123
to String
- 在
+
运算符中,如果其中一个操作数是字符串,那么另一个操作数会被转换为字符串
let num = 123;
let str = num + ""; // str 现在是字符串 "123"
- 在模板字符串中,
${}
内的表达式会被自动转换为字符串:
let num = 123;
let str = `${num}`; // str 现在是字符串 "123"
to Boolean
- 使用
!!
操作符:
let str = "hello";
let bool = !!str; // bool 现在是布尔值 true
- 在条件语句中,非布尔值会被自动转换为布尔值:
let str = "hello";
if (str) {
// str 被转换为 true
}