面试题
大家来看看这样一道面试题吧!它的结果是什么?
js
[]==![] //输出?true or false?
就这?一个这样的代码?小心有坑!大家好好思考一下!
我们学完今天的内容,带大家彻底学习完JavaScript中的类型转换!再最后为大家解答就会一目了然!
数据类型的转换
基本数据类型的转换
在JavaScript中,类型转换是指将一个值从一种类型转换为另一种类型。我们知道,JavaScript分为两大数据类型!
原始数据类型 和引用类型
我们先讲原始数据类型的转换,因为null
和undefined
是特殊的原始值,它们没有构造函数,不能像对象一样使用构造函数来创建他们的实例,所以我们不予研究。ES6也新增了Symbol
和BigInt
,其实他们类型转换基本机制相同,我们也不予研究。
我们在基本数据类型的转换当中研究:
- 原始值转布尔值
- 原始值转数字
- 原始值转字符串
- 原始值转对象
其实原始类型的转换还是很简单的,用一张图就可以为大家总结!
但是不用着急,我们一步一步走下去,带大家彻底理解!!
一、原始值转布尔值
js
// 原始值转布尔值
console.log(Boolean(false));//false
// 直接调用Boolean()是false
console.log(Boolean());//false
console.log(Boolean(1));//true
console.log(Boolean(0));//false
console.log(Boolean(-1));//true
console.log(Boolean(undefined));//false
console.log(Boolean(null));//false
console.log(Boolean('123'));//true
console.log(Boolean(''));//false
console.log(Boolean('0'));//true
console.log(Boolean(NaN));//false
布尔类型转布尔类型是不变的,为什么,我们接着往下看。
注意一点 !如果我们直接调用Boolean()
会返回默认的一个结果false
,
''
,null
和undefined
和NaN
和0
和'false'
传过来为什么是false
呢?
这是因为在 JavaScript 中,有一些值被视为"假值"(falsy values),它们在布尔上下文中被当作
false
。以下值在布尔上下文当中都会被当作为false
undefined
null
0
""
(空字符串)false
- NaN
对于NaN 和undefined 和 null 和 ""(空字符串),我觉得他们可以理解为直接调用
Boolean()
所以传过来的结果是false
其他所有值都被视为"真值",我们知道在布尔类型当中,0
为false
,其他值为true
,所以对于其他有值的原始值,结果就都是true
二、原始值转数字
js
console.log(Number());//0
console.log(Number('123'));//123
console.log(Number('hello'));//NaN 属于Number 代表无法表示的值
console.log(Number(undefined));//NaN
console.log(Number(null));//0
console.log(Number(true));//1
console.log(Number(false));//0
console.log(Number('12.14'));//12.14
console.log(Number('0012.14'));//12.14
console.log(Number('-12'));//-12
//字符串是数字就能转,还是是其他的字符串就不能转
与布尔一样,我们直接调用Number()
会默认返回地返回0
对于字符串,如果字符串当中夹杂了非组成数字的字符,那么这个字符串,无法转换为数字,而会被识别为NaN
Not a Number
大家不用担心-
和.
的问题,这些可以组成数字的字符是能够被Number
识别并且转换的,如果是0014
这种,它也会贴心地把前面的两个0
去掉,给你转换为14
。
而undefined
的这个原始值,会被识别为NaN
,而null
会被识别为0
,同样,布尔值转数字的话true
为1
,false
为0
。
三、原始值转字符串
js
//new String不传实参是一个空对象
console.log(String());//''
console.log(String(123));//'123'
console.log(String(NaN));//NaN
console.log(String(Infinity));//Infinity
console.log(String(undefined));//undefined
console.log(String(null));//null
console.log(String(true));//true
而原始值转字符串就相当简单粗暴了!直接将内容转换为字符串,不讲道理!
值得注意的就是,new String
不传实参其实就是一个空对象!
四、原始值转对象
js
console.log(Object());//{}
console.log(Object('123'));//[String: '123']
console.log(Object(123));//[Number: 123]
console.log(Object(null));//{}
console.log(Object(undefined));//{}
console.log(Object(true));//[Boolean: true]
console.log(Object(NaN));//[Number: NaN]
直接调用Object
构造函数,也是返回一个空对象,而除了null
和undefined
,会转为空对象除外,对于其他的原始值都会成功地转为对象!
同时,我们其实还可以这样转对象:
js
console.log(new Number(123));//[Number: 123]
没有,Object(123)
和new Number(123)
有异曲同工之妙!
引用类型的转换
引用类型的转换就有很多条条框框了,但是我们不用着急,我们来一步一步稳扎稳打,不踩坑!
不知道引用类型?大家可以去看看我的文章:[【爆肝干货】面试官:你能实现一下call()的源码嘛?今天我们就来搞懂call()源码instanceof源码和类型判断 - 掘金 (juejin.cn)](juejin.cn/post/730020...)
里面不仅仅讲了call()
源码,还有你想知道的数据类型。
一、对象转数字
传统方法
js
console.log(Number({}));//NaN
console.log(Number([]));//0
通过传统的办法,调用Number
直接转换也是可以的。我们可以看到对象转换为数字是NaN
,而空数组转换为数字是0
(这里我个人认为传的一个空数组,相当于直接调用Number()
不传实参一个意思。)
ValueOf()方法
JavaScript 中的 valueOf() 方法用于返回指定对象的原始值,若对象没有原始值,则将返回对象本身。valueOf()
方法,但是值得注意的是:valueOf()
只对包装类有用!也就是通过new
实现的对象!
Array:返回数组对象本身。
Boolean: 返回布尔值
Date:存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。
Function: 返回函数本身。
Number: 返回数字值。
Object:返回对象本身。这是默认情况。
String:返回字符串值。
Math 和 Error 对象没有 valueOf 方法。
js
//valueOf只对包装类有用
let a = new String('123')
console.log(a.valueOf());//123
let b = new Number(123);
console.log(b.valueOf());//123
官方文档对Object.valueOf()
这种调用方式也有介绍(链接给到这里哈~):es5.github.io/#x15.2.4.4
当然官方文档可是纯英文的!在这里强烈给大家安利一个Chrom小插件--沉浸式翻译!👍👍👍用过的都说好用!
很可惜,这里阿远也是么有看懂😳😳,大家先知道这个方法!待阿远闭关修炼一波~~🏄
官方也对To Number
也有描述(我们链接给到这里哈~):es5.github.io/#x8.12.8
二、对象转字符串
对象转字符串
js
let a = {}
console.log(String({}));//[object Object]
console.log(a.toString());//[object Object]
console.log(Object.prototype.toString.call(a))//[object Object]
我们可以通过三种方式String
和a.toString()
和Object.prototype.toString.call(a)
第一种String
String
其实就是new String
,将对象强制转换伪字符串值!
我们来给大家看看官方文档(地址阿远也给大家丢这里了哈!):es5.github.io/#x4.3.16
第二种toString
在JavaScript中,toString
是一个用于将对象转换为字符串的方法。
toString
方法会先对传进来的值进行分类,如果是对象,就会转换为字符串,再返回。
我们来看看官方文档的描述(es5.github.io/#x9.8):
第三种Object.prototype.toString.call(a)
这个方法在之前的文章:【爆肝干货】面试官:你能实现一下call()的源码嘛?今天我们就来搞懂call()源码instanceof源码和类型判断 - 掘金 (juejin.cn)中介绍过!
这个就是利用了原型链上Object
的原型上toString
,再利用call
将this
显式绑定在a
对象上,能够实现一个转字符串的效果,我们来看看官方文档(es5.github.io/#x9.8):
数组转字符串
我们再来说一下数组转字符串
js
let arr = [1,1,2,2]
// 数组调用toString是把数组里面的元素全部拿出来,以逗号进行拼接成一个字符串!
console.log(arr.toString())//输出:1,1,2,2
上文我们就介绍过,toString
方法会先对传进来的值进行一下类型判断。
如果是数组的话,那么toString
方法,会把数组当中的每一个元素,一个一个拿出来,用,
拼接成字符串!
时间转字符串
时间转字符串我们也要知道!
js
let time = new Date()
console.log(time.toString());//Tue Nov 21 2023 19:53:24 GMT+0800 (GMT+08:00)
同样,我们也可以通过toString
方法可以将时间转换为字符串
函数转字符串
函数转字符串也是调用toString
方法
js
var fn = function () {}
console.log(fn.toString());//function () {}
对象转布尔值
所有对象转布尔值都是true
,我们记住这一点就好了!
ToPrimitive()重要重要重要!!!
我们可以看到,在Number
和toString
的官方文档当中有一个ToPrimitive
方法,我们先为大家解释!
这个方法是我们JavaScript内置引擎自己调用的方法!
Number
的调用!
首先,如果传入的参数是一个基本类型的话,那么会直接返回!如果不是的话,会首先使用valueOf
方法转换,如果得到原始值,则返回,如果得不到,那么会调用toString
方法,如果得到原始值,则返回,如果还不行的话,就会报错了!
总结一下Number
的调用!
ToPrimitive(obj,Number) ===> Number({}) 先用valueOf转换 发现转换不了,用toString 成功,再就是原始值转原始值 js自己调用的方法
- 如果obj是基本类型,直接返回
- 否则,调用valueOf 方法,如果得到原始值,则返回
- 否则, 调用toString方法,如果得到原始值,则返回
- 否则, 报错
toString
的调用
在我们使用toString
的时候,我们的内核引擎会先判断,传进来的值如果是基本类型,也是直接返回,否则会先调用toString
方法,如果能得到原始值,就返回(注意!如果我们重写了toString
方法,会导致访问不到Object下的toString
方法),如果还不行,就会调用valueOf
方法,如果得到原始值,则返回!如果还不行就会报错!
总结toString
的调用
ToPrimitive(obj,toString) ===> String({})
- 如果obj是基本类型,直接返回
- 否则,调用 toString 方法,如果得到原始值,则返回 (假如,你再这个数据上重写了toString方法,导致访问不到Objcet下的toString方法)
- 否则, 调用 valueOf 方法,如果得到原始值,则返回
- 否则, 报错
我们再来看看官方文档!
其实,大家用着就会发现,似乎我们每次判断都不会用上valueOf
,那为什么这个步骤当中会加上valueOf
呢?
前面已经说了,valueOf
是可以转换包装类,之所以在Toprimitive
中加入valueOf
就是应对万一转换的就是包装类的情况,有时候,toString
方法也可能会在本数据当中被重写,也可以应对这种情况
运算符
JavaScript中有各种运算符,我们再简单学习一下一些运算符!
一元运算符
一元运算符有很多种例如:delete
,?
,!
,+
,-
等等
我们来一个案例学习一下+
js
console.log(+'1');//输出:1
console.log(+[]);//输出:0
console.log(+{});//输出:NaN
一元运算符+
会将操作数转换为Number
类型也就是说,上面案例当中的所有类型都要转换为Number
字符串转数字'1'
可以直接转换为1
,而[]
和{}
不同,我们来分析一下,
转数字,用第一个步骤调用toPrimitive
!首先,第一步不是基本类型,走第二步,使用valueOf
,我们在上文说过valueOf
对包装类才有效,是通过返回this
本身。什么是包装类?
"包装类"的概念通常与Java中的含义类似,也是用于将基本数据类型封装成对象
js
new Number()
new String()
new Boolean()
于是,我们的引擎会调用toString
方法,[]
变为字符串之后为一个''
空字符串,再去调用toNumber
于是得到了0
,我们可以参考上文官方文档的Number
转换,
同理,对于{}
要转换为数字,也是第一步走toPrimitive
方法,第一条和第二条都走不通!走toString
方法,对象调用toString
方法我们知道结果为:[object Object]
,再调用toNumber
于是结果输出NaN
非数字!
看看官方文档吧!
二元运算符
加法运算
我们直接看个案例,二元运算符a + b
这种
js
//二元运算符 例如a+b
console.log( 1 + '1');//11
//Number不传值都是0
console.log(1+null);//1
console.log([] + []);//空
//js中的隐式类型转换
console.log([] + {});//[object Object]
console.log({} + {});//[object Object][object Object]
1+'1'
因为运算当中存在字符串,所有二元运算符+
会把数字1
转换为字符串再与字符串'1'
相加,所以输出的结果是'11'
而对于传的值是1 + null
,二元运算因为参数有数字,所以会把其他参数转换为数字,而null
转换为数字就是0
,所以结果是1
而对于[] + []
和[] + {}
和{} + {}
,加法运算符会尝试将他们转换为字符串再进行拼接,所以我们看到的结果分别是空
和[object Object]
和[object Object][object Object]
我们看看官方文档如何描述的
==运算
对于==
运算符,我们来看看一个案例分析和过程大家就懂啦!
js
true == 1 // true
1 == {} => 1 == '[object Object]' => 1==NaN // false
{} == {} // false
console.log(false == []);// 0 == 0
对于true == 1
和1 == {}
和false == []
二元==
运算,它将会尝试去转换操作数到相同的类型,然后进行比较。
运算true == 1
和1 == {}
会将它们转换为数字进行比较!而false == []
怎么会尝试将[]
转换为布尔值进行运算!
最后答案揭晓!
js
[]==![] //输出?true or false?
我们拿到我们的题目!首先,我们观察到这个语句中有两个运算符==
和!
,我们要思考它们到底是怎样运算,我们就得知道它们的优先级!(运算符的优先级大家可以去查看一下),先告诉大家吧,!
的运算优先级更高,所以我们先得知道![]
是什么含义
取非,把它们绑在一起,我们知道==
会尝试将操作数转换为相同的类型,我们也这样做!
这里也涉及到了一个抽象相等比较法!(es5.github.io/#x11.9.3)
![]
转换为布尔是!true
也就是false
于是我们的运算为[] == false
,根据官方文档的抽象比较法的运算,==
会尝试将两边转换为数字
所以最终的效果为:0 == 0
结果为true
学到这里了!大家有任何疑问和改正欢迎留言评论哦~
不知道大家看完有没有收获,真的很用心去写哦,大家仔细看看,阿远还是希望大家能学到一些知识!
点个赞鼓励支持一下吧!🌹🌹🌹