【系列】深入理解 JavaScript 数据类型转换
上一期中我们主要是了解了 JavaScript 中存在两大数据类型:基本类型
和引用类型
以及其存储的方式(堆和栈)。
本期我们将重点谈谈 JavaScript 数据类型转换过程出现的各种“奇葩”的问题。
写在前面
在 JavaScript 中当运算符在运算时,如果两边数据不统一,CPU 就无法计算,这时我们编译器会自动将运算符两边的数据做一个数据类型转换,转成一样的数据类型再计算,这种无需程序员手动转换,而由编译器自动转换的方式就称为隐式转换。
在 JavaScript 中“一切皆是对象”,在我们具体了解隐式转换前先了解一下对象的两个方法:toString()
和valueOf()
。
toString()
toString() 方法返回一个表示该对象的字符串。
1 | // 数字转字符串 |
valueOf()
valueOf() 方法返回指定对象的原始值。
JavaScript 调用 valueOf 方法将对象转换为原始值。你很少需要自己调用 valueOf 方法;当遇到要预期的原始值的对象时,JavaScript 会自动调用它。
默认情况下,valueOf 方法由 Object 后面的每个对象继承。 每个内置的核心对象都会覆盖此方法以返回适当的值。如果对象没有原始值,则 valueOf 将返回对象本身。
JavaScript 的许多内置对象都重写了该函数,以实现更适合自身的功能需要。因此,不同类型对象的 valueOf()方法的返回值和返回值类型均可能不同。
1 | // 数字的原始值 |
隐式转换规则
- 转成 string 类型:+(字符串连接符)
- 转成 number 类型:++/–(自增或自减运算符)、+ - * / % (算术运算符)、> < >= <= == != === !== (关系运算符)
- 转成 boolean 类型:!(逻辑非运算符)
字符串 VS 加号连接符
字符串 + 基本类型 = 字符串 + String(基本类型)
1 | // 字符串 + 数字 |
数字 VS 加号连接符
数字 + 基本类型(非字符串) = 数字类型 + Number(基本类型)
1 | // 数字 + 布尔 |
数字 + 引用类型 = 数字 + 引用类型.toString()
1 | // 数字 + 数组 |
数字类型 + 函数 = 数字类型 + String(函数)
1 | // 数字 + 函数 |
关系运算符的隐式转换
规则:将其他数据类型转换成数字类型之后再比较关系
1 | // 字符串 vs 数字 = Number(字符串) vs 数字 |
逻辑非与关系运算符的隐式转换
1 | // 数字 vs 数组 = 数字 vs Number(数组) |
引用类型的隐式转换
规则:
- 当引用类型的 valueOf()调用时返回的值是一个基本类型时,则直接进行运算。
- 当引用类型的 valueOf()调用时返回的值不是一个基本类型时,则引用类型的 toString()将会被调用并返回转换后的字符串,然后再进行运算。
1 | // 字符串 + 数组 |
案例一:
目的:验证非自定义对象的隐式转换过程
1 | // 申明一个对象obj1 |
第一步:判断对象的 valueOf()返回值是否是基本类型
1 | console.log(obj1.valueOf()); // { age: 18 } |
第二步:调用对象的 toString()返回一个表示该对象的字符串
1 | console.log(obj1.toString()); // '[object Object]' |
第三步:根据运算规则进行运算(非字符连接操作都转换成 Number 进行运算)
1 | // 因为obj1.toString() 返回的是字符串,所以进行字符串连接操作 |
案例二:
目的:通过自定义对象的 valueOf()和 toString(),来验证对象的隐式转换过程
1 | // 申明一个对象obj2 |
第一步:判断对象的 valueOf()返回值是否是基本类型
1 | console.log(obj2.toString()); // '18' |
第二步:如果第一步能正确返回基本类型,则直接跳到第三步,否则将调用对象的 toString()返回一个表示该对象的字符串
1 | // 如果对象的valueOf()返回的是基本类型 |
第三步:根据运算规则进行运算(非字符连接操作都转换成 Number 进行运算)
1 | // 如果obj2的返回值是字符串,都进行字符串 VS 加号规则 |
特殊说明
JavaScript 中存在几个特殊的原始值:null、undefined、’’、0、NaN。
1 | console.log(typeof null); // object |
写在最后
通过上面对 JavaScript 中的数据类型的隐式转换可以总结出以下结论:
- JavaScript 中运算符在运算时,最终都将转换成相同类型进行运算(字符串类型、数字类型)
- 字符串与加号连接符运算时转换成 String 类型
- 非字符串加号连接符的运算都将转换成 Number 类型
- 特别注意引用类型的隐式转换是先判断 valueOf()返回的类型,如果返回是引用类型则调用 toString()返回对应的字符串值,最终都是按照 1,2,3 的规则进行运算。
以上内容虽然有进行验证,但不知道描述上是否存在歧义,有些点表述的不是很清楚,望谅解。
如果有发现任何问题或者有更好的建议,欢迎直接给我留言。