类型转换:编程中的桥梁与挑战
导读
在编程的世界里,数据是沟通的基石,而类型则是数据的形态和规则。不同的场景和操作要求数据以特定的类型存在。因此,类型转换成为了编程中不可或缺的一环,它如同一座桥梁,连接着数据处理的不同需求,同时也考验着程序员对数据类型的深刻理解和灵活运用。本文将结合官方文档深入探讨类型转换的概念、重要性、常见方式以及潜在的风险与最佳实践。
什么是类型转换?
类型转换,简而言之,就是在程序运行过程中,将一种数据类型转换为另一种数据类型的过程。这可以是自动完成的(由编译器或解释器隐式执行),也可以是显式通过代码指定的。类型转换的需要源于多种情况,比如函数参数类型不匹配、运算符对操作数类型有特定要求,或是数据存储与展示格式的差异等。
常见的类型转换方式
常见类型转换有原始值转布尔 Boolean(xx)
,原始值转数字 Number(xx)
,原始值转字符串 String(xx)
,原始值转对象 new Xxx()
以及 对象转原始值。这些类型转换又可以分为显示类型转换和隐式类型转换。
显示类型转换:使用Boolean(xx)
,Number(xx)
,String(xx)
以及new Xxx()
进行类型转换。
隐式类型转换:js执行引擎遵循一定的规则进行类型转换,这个过程你看不见。
其中重难点理解对象转原始值,由于其大部分是隐式转换,转换机制隐蔽,因此常常会出现一些令人难以理解的东西,如下:
都发生隐式转换:
+ '123' ==> 123
+ [] ==> 0
1 + '1' ==> '11'
null + 1 ==> 1
[] + {} ==> '[object Object]'
1 == {} // false
[] == ![] // true
而这些又经常在面试时会遇到,要你讲清楚原理。
要理解这些东西,需要借助官方文档阅读,究其根本。
1. XXX 转换成 Number,String,Boolean以及对象的结果
XXX | 转换为Number | 转换为String | 转换为Boolean |
---|---|---|---|
false | 0 | "false" | false |
true | 1 | "true" | true |
0 | 0 | "0" | false |
1 | 1 | "1" | true |
"0" | 0 | "0" | true |
"1" | 1 | "1" | true |
NaN | NaN | "NaN" | false |
Infinity | Infinity | "Infinity" | true |
-Infinity | -Infinity | "-Infinity" | true |
"" | 0 | "" | false |
"20" | 20 | "20" | true |
"twenty" | NaN | "twenty" | true |
[ ] | 0 | "" | true |
[20] | 20 | "20" | true |
[10,20] | NaN | "10,20" | true |
["twenty"] | NaN | "twenty" | true |
["ten","twenty"] | NaN | "ten,twenty" | true |
function(){} | NaN | "function(){}" | true |
{ } | NaN | "[object Object]" | true |
null | 0 | "null" | false |
undefined | NaN | "undefined" | false |
原始值转对象大部分都是new Xxx(),例如:new String("hello"),这不是重点,就一笔带过。
2. 对象转原始值详解
对象一般都是转字符串,数字,布尔。不会有谁闲着没事干去转null和undefined,毕竟没啥意义。
对象转布尔都是true,记住就行。
我们在查阅官方文档时发现,当是对象转**原始值(字符串,数字)**时,会调用一个函数ToPrimitive()
,接受一个参数,即表示期望的转换结果类型,可以是字符串或者数字。如下是转换为数字的例子:
是这么描述的:调用
ToPrimitive()
返回primValue
值,再用ToNumber()
将primValue
进行转换。
我们再来查看函数ToPrimitive()
干了件什么事:
对于原始类型,直接返回,这个好理解。
重点看对象是什么转换逻辑,点击8.12.8详解:
步骤概括如下:
-
- 调用toString方法,如果得到原始值,返回
-
- 否则,调用valueOf方法,如果得到原始值,返回
-
- 报错
补充: toString方法和valueOf方法转换规则:
-
- {}.toString() 得到由 "[object", class 和 “]”组成的字符串
-
- [].toString() 返回数组内部元素以逗号拼接的字符串
-
- xx.toString() 返回字符串字面量
- xx.toString() 返回字符串字面量
-
valueOf方法仅用于包装类:
综上所述,我们可以把ToPrimitive()
总结为以下步骤:
-
- 如果接收到的是原始值,直接返回值
-
- 否则,调用toString方法,如果得到原始值,返回
-
- 否则,调用valueOf方法,如果得到原始值,返回
-
- 报错
注意:注意如果是想把对象转化为数字则会先执行valueOf方法,反之,如果是想把对象转化为字符串则会先执行toString方法!
其最终是要把对象转成原始值。
运用类型转换解决疑难点
+ '123' ==> 123
+ [] ==> 0
1 + '1' ==> '11'
null + 1 ==> 1
[] + {} ==> '[object Object]'
1 == {} // false
[] == ![] // true
把这些问题归为三类:一元操作符,二元操作符以及 “==”运算。
对于一元操作符,官方文档如下描述:
// + '123' ==> 123
// ToNumber('123')
// 123
// + [] ==> 0
// ToNumber([])
// ToPrimitive([], Number)
// [].valueOf()
// [].toString() ====> ''
// ToNumber('')
// 0
对于二元操作符,官方文档如下描述:
// 1 + '1' ==> '11'
// ToPrimitive(1) + ToPrimitive('1')
// 1 + '1'
// ToString(1) + '1'
// '1' + '1'
// '11'
// null + 1
// ToPrimitive(null) + ToPrimitive(1)
// null + 1
// ToNumber(null) + ToNumber(1)
// 0 + 1
// 1
[] + {}
// oPrimitive([]) + ToPrimitive({})
// [].valueOf() + {}.valueOf()
// [].toString() + {}.toString()
// '' + '[object Object]'
// '[object Object]'
对于“==”运算,官方文档如下描述:
找到对应的情况:
[] == ![]
// [] == false
// [] == 0
// ToPrimitive([]) == 0
// '' == 0
// 0 == 0
// true
类型转换的挑战与风险
- 数据丢失:尤其是在从高精度类型转换到低精度类型时,如浮点转整数。
- 异常与错误:不恰当的转换可能导致运行时错误,如空指针异常、类型不匹配异常。
- 性能开销:频繁或复杂的类型转换可能引入额外的计算成本,影响程序效率。
- 可读性与维护性:过度依赖类型转换可能会使代码逻辑变得复杂,不利于阅读和维护。
结语:
通过以上深入的探讨,我们已经详尽地解析了类型转换在编程世界中的核心概念、常见方式、以及背后复杂的逻辑,尤其是对象到原始值转换的详细机制。
写作不易,觉得写的好的话,给个赞,感谢!!!
转载自:https://juejin.cn/post/7370980422901284879