细节解读JS隐式类型转换(js强制类型转换和隐式类型转换)
ECMAScript7规范中的ToPrimitive抽象操作
引用类型转化为原始类型最核心的其实就是这个内部抽象方法,这一块理解了,后面在做题目巩固的时候思路就很清晰了
Symbol --- @@toPrimitive
Symbol有很多有名的符号,
@@toPrimitive
,也就是Symbol.toPrimitive
,这是定义在Symbol
对象上的一个属性。
ToPrimitive(input [, PreferredType])
该抽象操作接受一个参数input
和一个可选的参数PreferredType
。该抽象操作的目的是把参数input
转化为非对象数据类型,也就是原始数据类型。如果input
可以同时转化为多个原始数据,那么会优先参考PreferredType
的值。转化过程参照下表:
参数input 的数据类型 | 结果 |
---|---|
Undefined | 返回input自身 |
Null | 返回input自身 |
Boolean | 返回input自身 |
Number | 返回input自身 |
String | 返回input自身 |
Symbol | 返回input自身 |
Object | 执行下面的步骤 |
如果input 的数据类型是对象,执行下述步骤: |
如果没有传入
PreferredType
参数,让hint
等于"default"
;如果
PreferredType
是hint String
,让hint
等于"string"
;如果
PreferredType
是hint Number
,让hint
等于"number"
;让
exoticToPrim
等于GetMethod(input, @@toPrimitive)
,大概语义就是获取参数input
的@@toPrimitive
方法;如果
exoticToPrim
不是Undefined
,那么:让
result
等于Call(exoticToPrim, input, « hint »)
,大概语义就是执行exoticToPrim(hint)
;如果
result
是原始数据类型,返回result
;抛出类型错误的异常;
如果
hint
是"default"
,让hint
等于"number"
;返回
OrdinaryToPrimitive(input, hint)
抽象操作的结果。
总结:
判断PreferredType,
只要传的值不是
string,最后统一算作
number`@@toPrimitive
方法优先级高于OrdinaryToPrimitive(input, hint)
,如果前者能返回原始类型那就不需要执行后面的操作了如果
@@toPrimitive
方法不存在或者存在返回的值不是原始类型,继续执行OrdinaryToPrimitive(input, hint)
操作
疑问:hint是什么?怎么传的?(继续往下看)
OrdinaryToPrimitive(O, hint)
O
的数据类型是对象,hint
的数据类型是字符串,并且hint
的值要么是"string"
,要么是"number"
。该抽象操作的步骤如下:
如果
hint
是"string"
,让methodNames
等于« "toString", "valueOf" »
;如果
hint
是"number"
,让methodNames
等于« "valueOf", "toString" »
;按顺序迭代列表
methodNames
,对于每一个迭代值name
:让
method
等于Call(method, O)
,大概语义就是执行method()
;如果
result
的类型不是对象,返回result
;让
method
等于Get(O, name)
,大概语义就是获取对象O
的name
值对应的属性;如果
method
可以调用,那么:抛出类型错误的异常。
由上述操作步骤可知:
通过
ToPrimitive
的步骤6
可知,当没有提供可选参数PreferredType
的时候,hint
会默认为"number"
;通过
ToPrimitive
的步骤4
可知,可以通过定义@@toPrimitive
方法来覆盖默认行为,比如规范中定义的Date
日期对象和Symbol
符号对象都在原型上定义了@@toPrimitive
方法。
总结:
如果
hint
是"string"
,先执行toString
,如果没有返回原始值继续执行valueOf
方法如果
hint
是"number"
,先执行valueOf
,如果没有返回原始值继续执行toString
方法
hint
hint可以理解为根据场景自动判断
更倾向于
转换成string
还是number
,如果无法判断倾向于转化哪一个,就是default
。下面我们来模拟
一下转化过程中获取hint值的过程
const obj = { [Symbol.toPrimitive](hint) { console.log(`hint: ${hint}`); } }; const arr = [] arr[obj] // hint: string 复制代码
const obj = { [Symbol.toPrimitive](hint) { console.log(`hint: ${hint}`); } }; -obj // hint: number 复制代码
var a = [1, 2, 3] a[Symbol.toPrimitive] = function (hint) { console.log(`hint: ${hint}`); } '' + a // hint: default 复制代码
总结:
1、引用类型转化的时候,先确定是否有@@toPrimitive
方法,优先级高于OrdinaryToPrimitive(input, hint)
,如果前者能返回原始类型那就不需要执行后面的操作了
2、判断hint值
3、如果hint
是"string"
,先执行toString
,如果没有返回原始值继续执行valueOf
方法
4、如果hint
是"number"
,先执行valueOf
,如果没有返回原始值继续执行toString
方法
作者:今天砖有点烫手
链接:https://juejin.cn/post/7036670291044466695
伪原创工具 SEO网站优化 https://www.237it.com/