-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
重学js —— 类型转换 #54
Comments
Open
Open
Open
This was referenced Feb 11, 2020
This was referenced Feb 21, 2020
Open
Open
This was referenced Mar 26, 2020
This was referenced Apr 6, 2020
This was referenced Apr 24, 2020
This was referenced May 5, 2020
This was referenced May 25, 2020
Open
This was referenced Jun 2, 2020
This was referenced Jun 10, 2020
This was referenced Jun 20, 2020
This was referenced Jun 28, 2020
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
抽象运算 —— 类型转换
阅读这章之前,先思考下面代码:
老实说,我不能完全正确说出结果,也不能保证说出 为什么?
正因为我的js基础如此之垃圾,所以阅读规范中关于类型转换一章并翻译,同时配合MDN进行学习,希望有底气的回答上面代码的表现行为及原因。
正文
当需要时,ECMAScript会自动隐式执行类型转换。类型转换抽象运算只能接收 ECMAScript语言类型,不能接收 规范类型。
ToPrimitive ( input [ , PreferredType ] )
将输入的
input
转换为非Object
类型值。如果对象能够转换为多个原始类型,则可以使用可选提示PreferredType
来确定需要转换成哪个类型。input
是Object
类型PreferredType
不存在,定义过程变量hint
赋值为"default"
PreferredType
是String
,定义过程变量hint
赋值为"string"
PreferredType
是Number
hint
赋值为"number"
exoticToPrim
,执行GetMethod(input, @@toPrimitive)并赋值给exoticToPrim
exoticToPrim
不是undefined
,result
,调用Call(exoticToPrim, input, « hint »)
并赋值给result
,result
不是Object
类型则返回result
hint
是"default"
,将hint
赋值为"number"
OrdinaryToPrimitive(input, hint)
的返回值input
一开始就不是Object
类型,直接原路返回OrdinaryToPrimitive ( O, hint )
主要是为了将
Object
转为 原始数据类型。O
必须是对象hint
必须是String
类型且值为"string"
或"number"
hint
是"string"
methodNames
,值为List« "toString", "valueOf" »
hint
是"number"
methodNames
,值为List« "valueOf", "toString" »
methodNames
这个List,定义过程变量name
来缓存List中的每个值method
,执行Get(O, name)
赋值给method
true
result
,执行 Call(method, O)赋值给result
(这里本质上就是在执行 valueOf() 或 toString(),先后顺序看methodNames
这个List)result
不是Object
,则返回result
ToBoolean ( argument )
直接看表就好:
false
,其余都是true
false
,否则都是true
false
,其余都是true
ToNumeric ( value )
顾名思义,转为数值的,只不过有
Number
和BigInt
两种可能。ToNumber ( argument )
这个是转换为
Number
类型的了。见下表:true
=> 1,false
=> +0Number
注意:
2019.11.14号,ECMAScript262规范目前规定传入BigInt参数会报错,从测试来看,使用 + 操作应该默认的是ToNumber,符合要求;但是使用Number()却能正常转换,而该算法内部依然使用ToNumber,却不报错?
我去知乎提过这个问题,有大佬指出这是规范编写时的bug,还没有修复,见知乎。
根据链接我去查看了issue里面的其它链接,ToNumber ( argument )这里依然是抛类型错误,但是下面的 注意 告诉我:
此外,最新的BigInt 文档补丁里的Number(value)方法内部把ToNumber(value) 改成 ToNumeric(value)了
String转Number
针对String转Number,如果语法无法将String解释为StringNumericLiteral的扩展,则ToNumber的结果为 NaN。
注意:
StringNumericLiteral
可以包括 前导 和 尾随空白 以及 行终止符StringNumericLiteral
可以具有任意数量的前导 0 数字StringNumericLiteral
可以包含 + 或 - 表示其符号StringNumericLiteral
会转换为 +0。Infinity
和-Infinity
被StringNumericLiteral
认可,但它们不是 NumericLiteralStringNumericLiteral
不能包含 BigIntLiteralSuffixString
类型的数字转换为Number
类型的数字见:https://tc39.es/ecma262/#sec-runtime-semantics-mv-s测试:
ToInteger( argument )
ToNumber(argument)
并将值赋给过程变量number
number
是NaN
,则返回 +0number
是+0, -0, +Infinity 或 -Infinity
,则直接返回number
(这里用Infinity
代替规范中的∞
符号)number
相同符号的 Number类型值,其大小是floor(abs(number))
。先取正,再四舍五入。ToInt32 ( argument )
将
argument
转成32位(4字节)有符号的整数,取值范围在 Math.pow(2, -31) ~ Math.pow(2, 31) - 1 之间。ToNumber(argument)
并将值赋给过程变量number
number
是NaN
,+0
,-0
,+Infinity
或-Infinity
,则返回 +0int
,其值是 与number
相同符号的 Number类型值且其大小是floor(abs(number))
int32bit
,其值为对int
执行 2的32次幂 按模运算int32bit
>= 2的31次幂,返回int32bit - 2的32次幂
;否则返回int32bit
ToUint32 ( argument )
将
argument
转成32位无符号的整数,取值范围在 0 ~ Math.pow(2, 32) - 1 之间。ToInt32
一致int32bit
ToInt16 ( argument )
转为16位(2字节)有符号整数,取值范围在 -32768 ~ 32767
ToInt32
一致int16bit
,其值为对int
执行 2的16次幂 按模运算int32bit
>= 2的15次幂,返回int16bit - 2的16次幂
;否则返回int16bit
ToUint16 ( argument )
转为16位(2字节)无符号整数,取值范围在 0 ~ Math.pow(2, 16) - 1
ToInt16
一致int16bit
ToInt8 ( argument )
转为 8 位有符号整数,取值范围在 -128 ~ 127,即 Math.pow(2, -7) ~ Math.pow(2, 7) - 1
ToInt16
一致int8bit
,其值为对int
执行 2的8次幂 按模运算int8bit
>= 2的7次幂,返回int8bit - 2的8次幂
;否则返回int8bit
ToUint8 ( argument )
转为 8 位无符号整数,取值范围在 0 ~ 255,即 0 ~ Math.pow(2, 8) - 1
ToInt8
一致int8bit
ToUint8Clamp ( argument )
目的和
ToUint8
一样,但是过程不一样number
,将ToNumber(argument)
结果赋值给number
number
是NaN
,返回 +0number
<= 0, 返回 +0number
>= 255, 返回 255f
,对number
四舍五入并赋值给f
f
+ 0.5 <number
,返回f
+ 1f
+ 0.5 >number
, 返回f
f
是奇书,返回f
+ 1f
ToBigInt ( argument )
prim
,执行ToPrimitive(argument, hint Number)
将结果赋值给prim
prim
值对照下表返回prim
NaN
,返回类型错误,否则返回结果其实这里对
Number
类型的参数执行结果和上面的ToNumber
一样令人困惑,但这里的本意是指 禁止我们开发中将Number隐式转换为BigInt,要想转换,必须显式调用根据 重学js —— js数据类型:BigInt 对象 一章,
BigInt(Number 类型值)
会做特殊处理,不会走ToBigInt
方法StringToBigInt ( argument )
调用 https://tc39.es/ecma262/#sec-tonumber-applied-to-the-string-type 处的算法,略微有点不同:
NaN
,返回NaN
;否则,返回完全对应于数学值的BigInt,而不是四舍五入为数字。ToBigInt64 ( argument )
转换为64位有符号整数值,取值范围 Math.pow(2, -63) ~ Math.pow(2, 63) - 1
n
,调用ToBigInt(argument)
将结果赋值给n
int64bit
,对n
进行2的64次幂 取模运算,将结果赋值给int64bit
int64bit
>= Math.pow(2, 63),返回int64bit
- Math.pow(2, 64);否则返回int64bit
ToBigUint64 ( argument )
转换为64位无符号整数值,取值范围 0 ~ Math.pow(2, 64) - 1
ToBigInt64
一致int64bit
ToString ( argument )
见表:
ToPrimitive(argument, hint String)
将值赋给primValue
,再返回ToString(primValue)
ToObject ( argument )
见下表:
[[BooleanData]]
内置插槽值为argument,详见Boolean Objects[[NumberData]]
内置插槽值为argument,详见Number Objects[[StringData]]
内置插槽值为argument,详见String Objects[[SymbolData]]
内置插槽值为argument,详见Symbol Objects[[BigIntData]]
内置插槽值为argument,详见BigInt ObjectsToPropertyKey ( argument )
听名字就知道,转换成对象能用的属性类型:String 和 Symbol
ToLength ( argument )
给类数组对象用的,确定其长度
ToInteger(argument)
并赋值给len
len
<= +0,返回 +0CanonicalNumericIndexString ( argument )
如果是ToString会生成的Number的字符串表示形式,则返回转换为数值的参数,或者是字符串
"-0"
。否则返回undefined
。有点绕人,就是看
argument
能不能转换成Number
,不能返回undefined
,能得话区分-0
。ToIndex ( value )
如果是有效的整数索引值,则将其值参数转换为非负整数。
回归代码
回到开篇给出的那些代码,结合规范,其中一些代码能直接给出原因,例如:
但是还有很多代码,仍需要深究为什么?
例如以下代码,需要看Number::toString(argument)
还有与对象相关的转换为
Number
或String
:上面不论是转为
Number
还是String
,其本质都需要调用 ToPrimitive 算法,问题的关键点就在该算法内部调用的OrdinaryToPrimitive算法的规则。其实本质上就是调用对象的valurOf()
或toString()
实现个ToPrimitive
参考
2020-07-29 补充
数组类型转换时犯浑了!
我误以为数组和对象的
toString
返回一致,其实我记错了,原题啊都能记错!!!我TM看到
[1, 2]
这种心想怎么转为数值啊?是不是转为"[object Array]"
啊???其实数组转为原始值,存在多个元素的话会通过类似
join(',')
的操作转为字符串的!!!The text was updated successfully, but these errors were encountered: