前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript|类型转换,你真的会么?

JavaScript|类型转换,你真的会么?

作者头像
Java小技巧
发布2022-05-23 12:56:12
3870
发布2022-05-23 12:56:12
举报
文章被收录于专栏:Java小技巧Java小技巧

01

类型转换定义

众所周知 JS 是弱类型语言,所以类型转换发生非常频繁,大部分我们熟悉的运算都会先进行类型转换。大部分类型转换符合人类的直觉,但是如果我们不去理解类型转换的严格定义,很容易造成一些代码中的判断失误。

其中最为尴尬的是 JavaScript 中的“ == ”运算,因为试图实现跨类型的比较,它的规则复杂到几乎没人可以记住。

它属于设计失误,并非语言中有价值的部分,很多实践中推荐禁止使用“ ==”,而要求程序员进行显式的类型转换后,用“===”比较。

其它运算,如加减乘除大于小于,也都会涉及类型转换。大部分类型转换规则是非常简单的,如下表所示:

较为复杂的部分是 Number 和 String 之间的转换,以及对象跟基本类型之间的转换。

02

StringToNumber

字符串到数字的类型转换,存在一个语法结构,类型转换支持十进制、二进制、八进制和十六进制,比如:

30、0b111、0o13、0xFF。

此外,JavaScript 支持的字符串语法还包括正负号科学计数法,可以使用大写或者小写的 e 来表示:

1e3、-1e-2。

parseInt 和 parseFloat 并不使用这个转换,所以支持的语法跟这里不尽相同。

在不传入第二个参数的情况下,parseInt 只支持 16 进制前缀“0x”,而且会忽略非数字字符,也不支持科学计数法。在一些古老的浏览器环境中,parseInt 还支持 0 开头的数字作为 8 进制前缀,这是很多错误的来源。

parseInt-谷歌:

parseInt-IE8:

所以在任何环境下,都建议传入 parseInt 的第二个参数,而 parseFloat 则直接把原字符串作为十进制来解析,它不会引入任何的其他进制。多数情况下,Number 是比 parseInt 和 parseFloat 更好的选择。

03

NumberToString

在较小的范围内,数字到字符串的转换是完全符合十进制表示。当 Number 绝对值较大或者较小时,字符串表示则是使用科学计数法表示的。

开发中使用较少,具体的细节,可以去参考 JavaScript 的语言标准

04

装 箱 转 换

每一种基本类型 Number、String、Boolean、Symbol 在对象中都有对应的类,所谓装箱转换,正是把基本类型转换为对应的对象,它是类型转换中一种相当重要的种类。

全局的 Symbol 函数无法使用 new 来调用,但可以利用装箱机制来得到一个 Symbol 对象,可以利用一个函数的 call 方法来强迫产生装箱。

定义一个函数,函数里面只有 return this,然后我们调用函数的 call 方法到一个 Symbol 类型的值上,这样就会产生一个 symbolObject。

用 console.log 看一下这个东西的 type of,它的值是 object,使用 symbolObject instanceof 可以看到,它是 Symbol 这个类的实例,找它的 constructor 也是等于 Symbol 的,所以无论从哪个角度看,它都是 Symbol 装箱过的对象:

装箱机制会频繁产生临时对象,在一些对性能要求较高的场景下,应该尽量避免对基本类型做装箱转换。

使用内置的 Object 函数,可以在 JavaScript 代码中显式调用装箱能力:

每一类装箱对象皆有私有的 Class 属性,这些属性可以用 Object.prototype.toString 获取:

在 JavaScript 中,没有任何方法可以更改私有的 Class 属性,因此 Object.prototype.toString 是可以准确识别对象对应的基本类型的方法,它比 instanceof 更加准确。

需要注意的是,call 本身会产生装箱操作,所以需要配合 typeof 来区分基本类型还是对象类型。

05

拆 箱 转 换

在 JavaScript 标准中,规定了 ToPrimitive 函数,它是对象类型到基本类型的转换(即,拆箱转换)。对象到 String 和 Number 的转换都遵循“先拆箱再转换”的规则。

通过拆箱转换,把对象变成基本类型,再从基本类型转换为对应的 String 或者 Number。

拆箱转换会尝试调用 valueOf 和 toString 来获得拆箱后的基本类型。如果 valueOf 和 toString 都不存在,或者没有返回基本类型,则会产生类型错误 TypeError。

定义一个对象 o,o 有 valueOf 和 toString 两个方法,这两个方法都返回一个对象,然后我们进行 o*2 这个运算的时候,先执行了 valueOf,接下来是 toString,最后抛出了一个 TypeError,这就说明了这个拆箱转换失败了。

到 String 的拆箱转换会优先调用 toString。把刚才的运算从 o*2 换成 String(o),那么调用顺序就变了:

在 ES6 之后,还允许对象通过显式指定 @@toPrimitive Symbol 来覆盖原有的行为:

06

"类 型" 争 议

“类型”在 JavaScript 中是一个有争议的概念。一方面,标准中规定了运行时数据类型;另一方面,JavaScript 语言中提供了 typeof 这样的运算,用来返回操作数的类型,但 typeof 的运算结果,与运行时类型的规定有很多不一致的地方。

如下表:

表格中,多数项是对应的,但是请注意 object——Null 和 function——Object 是特例,理解类型的时候需要特别注意这个区别。

从一般语言使用者的角度来看,毫无疑问,应该按照 typeof 的结果去理解语言的类型系统。

JavaScript 之父本人也在多个场合表示过,typeof 的设计是有缺陷的,只是现在已经错过了修正它的时机。

end

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java小技巧 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档