1、显示转换:
显示转换的方法Number、String、Boolean、parseInt、parseFloat、toString 等等
ToNumber
String 转换为 Number 类型的规则:
- 如果字符串中只包含数字,那么就转换为对应的数字。
- 如果字符串中只包含十六进制格式,那么就转换为对应的十进制数字。
- 如果字符串为空,那么转换为0。
- 如果字符串包含上述之外的字符,那么转换为 NaN。
ToBoolean
Symbol可以转换为true
ToString
常见面试题:
为什么 [1, 2, 3].map(parseInt) 返回 [1,NaN,NaN]?
答:
map内部实际执行的为parseInt(1, 0)、parseInt(2, 1)、parseInt(3, 2),第几个item和index默认作为了parseInt的两个参数
parseInt(string, radix) 的参数radix必须介于2~36之间,而且字符串string中的数字不能大于radix才能正确返回数字结果值。
parseInt(‘1’,0) = 1
parseInt(‘2’,1) = NaN
parseInt(‘3’,2) = NaN
参考:https://blog.csdn.net/freshlover/article/details/19034079/
2、隐式类型转换
隐式类型转换一般是在涉及到运算符的时候才会出现的情况,比如我们将两个变量相加,或者比较两个变量是否相等。
2.1、判断相等类型转换表
总结一些转换规则:
- 类型相等不进行转换
- null和undefined之间相互相等,与其他类型都不相等
- 转换为的类型可以为Number和String类型,优先级为Number > String
- 两个基本类型转为都为ToNumber
- 引用类型与String类型比较不转换,与其他基本类型比较基本类型都转换为Number类型
- 引用类型发生转换使用ToPrimitive方法
看一下ToPrimitive的源码
// 获取类型
const getType = (obj) => {
return Object.prototype.toString.call(obj).slice(8,-1);
}
// 是否为原始类型
const isPrimitive = (obj) => {
const types = ['String','Undefined','Null','Boolean','Number'];
return types.indexOf(getType(obj)) !== -1;
}
const ToPrimitive = (input, preferredType) => {
// 如果input是原始类型,那么不需要转换,直接返回
if (isPrimitive(input)) {
return input;
}
let hint = '',
exoticToPrim = null,
methodNames = [];
// 当没有提供可选参数preferredType的时候,hint会默认为"default";
if (!preferredType) {
hint = 'default'
} else if (preferredType === 'string') {
hint = 'string'
} else if (preferredType === 'number') {
hint = 'number'
}
exoticToPrim = input.@@toPrimitive;
// 如果有toPrimitive方法
if (exoticToPrim) {
// 如果exoticToPrim执行后返回的是原始类型
if (typeof (result = exoticToPrim.call(O, hint)) !== 'object') {
return result;
// 如果exoticToPrim执行后返回的是object类型
} else {
throw new TypeError('TypeError exception')
}
}
// 这里给了默认hint值为number,Symbol和Date通过定义@@toPrimitive方法来修改默认值
if (hint === 'default') {
hint = 'number'
}
return OrdinaryToPrimitive(input, hint)
}
const OrdinaryToPrimitive = (input, hint) => {
let methodNames = null,
result = null;
if (typeof input !== 'object') {
return;
}
// 这里决定了先调用toString还是valueOf
if (hint === 'string') {
methodNames = [input.toString, input.valueOf]
} else {
methodNames = [input.valueOf, input.toString]
}
for (let name in methodNames) {
if (input[name]) {
result = input[name]()
if (typeof result !== 'object') {
return result
}
}
}
throw new TypeError('TypeError exception')
}
ToPrimitive方法解读:
参数:
@input为转换的对象
@preferredType为转换的类型,支持无、Number、String
- 判断input为基本类型直接返回
- 赋值传入的preferredType类型
- 判断引用类型是否有@@toPrimitive方法,如果有使用exoticToPrim.call获取对应的值。值为基本类型直接返回,否则报错
- 如果preferredType是无赋值为默认的Number类型
- 调用OrdinaryToPrimitive
OrdinaryToPrimitive方法解读:
参数:
@input为转换的对象
@hint为转换的类型,支持、Number、String
- 判断input不为引用类型直接返回
- (1)判断如果hint为String类型,先调用toString方法返回原始类型直接返回,否则调用valueOf方法判断是原始类型直接返回,否则报错。(2)判断如果hint为Number类型,先调用valueOf方法返回原始类型直接返回,否则调用toString方法判断是原始类型直接返回,否则报错
如果传入参数是string,也就是对象到字符串的转换,经过了如下步骤:
- 如果对象中有toString()方法,则调用这个方法。如果它返回一个原始值(undefined、Boolean、Number、String、BigInt、Symbol 和 null),js将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串结果。
- 如果对象没有toString()方法,或者toString()没有返回一个原始值,那么js会调用valueOf()方法。如果返回值是原始值,js将这个值转换为字符串,并返回字符串结果。
- 否则,js抛出一个类型错误异常。
如果传入参数是number/default,也就是对象到数字的转换,经过了如下步骤:
和上面有点不同,到数字的转换会先尝试使用valueOf()方法
- 如果对象具有valueOf()方法,后者返回一个原始值,则js会将其转换为数字(如果需要的话)并返回这个数字。
- 否则,如果对象具有toString()方法,返回一个原始值(字符串直接量),则js将其转换为数字类型,并返回这个数字。
- 否则,js抛出一个类型错误异常
字符串连接符
+两边有一边是字符串,那这个+就是字符串连接符,它会把其他数据类型调用String()方法转成字符串然后拼接;
引用类型使用valueOf和toString转换
数组:
对象:
函数:
特殊的对象:日期对象自定义了toString和valueOf[
](https://zhuanlan.zhihu.com/p/85731460)
实例讲解:
1、[] == 0
(1)[].valueOf() 得到[],还是引用类型继续转换
(2)[].toString() 得到””
(3)判断对比的为0,使用Number(“”) == 0
(4)结果为true
2、![] == 0
(1)逻辑非优先级高于关系运算符,![]转换为false
(2)判断对比的为0,使用Number(false) == 0
(3)结果为true
3、[] == ![]
(1)右边![],逻辑非运算符优先级比较高,![]转换为false
(2)判断右边不为字符串先使用valueOf转换,[].valueOf() 得到[],还是引用类型继续转换
(3)[].toString() 得到””
(4)Number(“””) == Nunber(false)
(5)结果得到true
4、[] == []
(1)判断两边都为引用类型,不发生转换
(2)虽然都为空数组,但是对比的为内存地址
(3)结果为false
5、{} == !{}
(1)右边!{},逻辑非运算符优先级比较高,!{}转换为false
(2)判断右边不为字符串先使用valueOf转换,{}.valueOf() 得到{},还是引用类型继续转换
(3)[].toString() 得到”[object Object]”
(4)Number(“[object Object]”) == Number(false)
(5)结果为false
6、{} == {}
(1)判断两边都为引用类型,不发生转换
(2)虽然都为空对象,但是对比的为内存地址
(3)结果为false
7、date对象+
(1)判断是+走字符串拼接
(2)d.toString() 转换为美式日期字符串 + 1 字符串拼接
8、date对象-
(1)判断是-,转换为Number类型计算
(2)d.valueOf() 转换为时间戳 - 1 计算
9、字符串与任何类型+,任何类型都会转换为字符串类型
10、- * / 这类只能使用Number类型运算,所以转换为Number类型
11、111 < “b” || “b” > 111
(1)由于Number优先级比较高,所以”b”转换为Number
(2)Number(“b”)等于NaN
(3)NaN < 111得不出判断结果
(4)结果为false
12、”111” < “b”
(1)字符串比较使用.charCodeAt()比较字符串首个的Unicode编码值
(2)”111”.charCodeAt()为49,”b”.charCodeAt()为98
(3)结果为true
类似的情况,”a1212”.charCodeAt()为97,所以为true
字符串能转换成Number的,比较还是转换成Number去比较
==和===的区别:
==判断时会发生隐式转换、===判断时即判断值相等又判断类型相等
日常使用:不用==判断,会造成意图不明确不便于日后维护
参考链接:https://www.jianshu.com/p/6ac1397e944c
参考:
https://zhuanlan.zhihu.com/p/85731460
https://blog.csdn.net/freshlover/article/details/19034079/
https://juejin.cn/post/7013933952436011039#heading-6