摘要
js 的数据类型转换也属于是面试的常客之一,而隐式转换尤为重要并且相应难度也较高,所以关于数据类型的转换我们一定要仔细了解清楚。
数据类型转换的介绍
在 JavaScript 中,值从一种数据类型自动或手动转换为另一种数据类型的过程。而这里所谓的手动转换就是显示类型转换,自动转换就是隐式类型转换。
类型:String, Number, Boolean, Object, null, undefined, Symbol
显示类型转换
解释: 开发者主动使用内置函数或操作符明确指示将值转换为特定类型。
显示类型转换中有三种,这三种分别为:转换为 Number,转换为 String,转换为 Boolean
(注意:undefined 是一个没有定义的值,无法转换数据类型,null 同样做不到,Sympol 和bigInt 都是后来增加的数据类型,功能单一,也不支持数据类型的转换。)
我们先来看一串代码和一张图:
let a = 1
let b = String(a)
let c = Boolean(a)
let d = '123'
let e = Number(d)
let f = Boolean(d)
console.log(b, c, e, f);
console.log(typeof a);
console.log(typeof b);
console.log(typeof c);
console.log(typeof d);
console.log(typeof e);
console.log(typeof f);
由此我们可以看到,可以通过这些函数的转换将原数据类型转换成我们想让它变成的数据类型。
转布尔Boolean() 和 数字Number()
原始类型转原始类型:
//转布尔:
console.log(Boolean()); // false 没传值
console.log(Boolean(undefined)); // false if他默认将括号内的数据转换成布尔型,所以没值就是false
console.log(Boolean(null)); // false
console.log(Boolean(0)); // false 只要是数字,不为0都是true
console.log(Boolean(-0)); // false
console.log(Boolean(-1)); // true
console.log(Boolean(NaN)); // false NaN(一个number类型)是一个无法描述的数字
console.log(Boolean('')); // false
console.log(Boolean('abc')); // true
//undefined,0,null,空字符串输出都为 false
//转数字:https://es5.github.io/#x15.7.1.1(官方规则)
//当传入的字符串是纯数字时才能转换成数字,有任何一个其他
字符都将是 NaN
console.log(Number('123')); // 123
console.log(Number('')); // 0 空字符串为0
console.log(Number('hello')); // NaN(not a number)
console.log(Number()); // 0 空
转字符串 String()es5.github.io/#x15.5.1.1
隐式类型转换
- 隐式类型转换(都是朝原始类型转)
比如以下就是为了比较而自发的进行隐式类型转换
- 原始类型转原始类型
和显示转换规则一样,只是用过一些符号(比如:!,+等)让程序自己发生隐式的数据类型转换。
- 引用类型转原始类型
(注:显示类型转换也有引用类型转原始类型,只是都拿到这来讨论)
1. 转布尔 --- 任何引用类型转布尔 都是 true(官方文档定义)
2. 转字符串 --- String(obj) ==> ToString(obj) ==> ToPrimitive(obj, String) //(obj 为传入的需要转换的对象)
3. 转数字 --- Number(obj) ==> ToNumber(obj) ==> ToPrimitive(obj, Number)
ToPrimitive (es5.github.io/#x9.1 / es5.github.io/#x8.12.8)
- ToPrimitive(obj, String)
//以下是对8.12.8 的总结概括
- 判断 obj 是否为原始类型,是则直接返回
- 否则,调用 toString(), 如果得到了原始类型,则返回
- 否则,调用 valueOf(), 如果得到了原始类型,则返回
- 否则,抛出 TypeError 异常
- ToPrimitive(obj, Number)
- 判断 obj 是否为原始类型,是则直接返回
- 否则,调用 valueOf(), 如果得到了原始类型,则返回
- 否则,调用 toString(), 如果得到了原始类型,则返回
- 否则,抛出 TypeError 异常
valueOf()(出现在Object 原型上)
不可以转换
可以转换:
- valueOf在对象的原型上,它只能将包装类(new 出来的。(像 let s = 'hello' 就是new出一个s,因为这是执行规则))的对象转为原始类型
toString()
- js中大部分的构造函数原型上都重写了
toString方法
- {}.toString 返回由'[object' 和 [[class]] 和 ']' 组成的字符串
- [].toString 返回由数组中每个元素以逗号拼接而成的字符串
- xxx.toString 直接返回 xxx 的字符串字面量
当对象访问的是 Object 的 toString 时,那返回的将是 '[object XX]',当访问的是 它本身的 toString (比如:Array.toString)时,返回的是
'==' 与 '==='的区别
JavaScript 中,==(宽松相等)和 ===(严格相等)是两种完全不同的比较运算符,核心区别在于是否进行类型转换。
-
== 会发生隐式类型转换,所以只判断值是否相等
-
=== 不会发生类型转换,所以会判断值和类型是否相等
在我们写代码要比较值时尽量写成'===',几乎所有场景所需的比较都可以用'==='实现,并且'==='更为严谨,可避免隐式转换带来的意外结果。
发生隐式类型转换的场景
- 四则运算 +, -, *, /, %,
- 判断语句 if, while, ==, >=, <=, !=, >, <。
+号 的使用规则(es5.github.io/#x11.6.1)
- 作为一元运算符 -- 会发生隐式类型转换,转成 number (执行 + '123' 时,只有一边是字符串那就只返回这个字符串)
- 作为二元运算符 -- 只要+左右两边有一个是字符串,那么另一个也会转字符串进行拼接(将两边加起来一起输出)
面试经典考题:
1:
输出为:true
因为 !的优先级大于 ==
- !会先将 [] 转为 true(原始类型转任何引用类型都为 true)
- 然后 ![] 为 false
- 而比较绝大多数情况都是将两类型转为数字再进行比较,右边变为 0。
- 左边被 toString (这个 toString 是数组自己身上的函数,不是 Object 的,所以会得到一个空字符串 ' ')
- 空字符串调用 Number 函数返回的是 0,所以是true。
2:
{} + []
答案:'[object Object]' (就是:'[object Object]' + '')
{} 是对象调用 toString ,就是调用自己(Object)的 toString ,所以返回:'[object Object]'