面试题:[]==![] 结果是true or false ?带大家彻底搞懂JS类型转换机制 通宵爆肝!

面试题

大家来看看这样一道面试题吧!它的结果是什么?

js 复制代码
[]==![] //输出?true or false?

就这?一个这样的代码?小心有坑!大家好好思考一下!

我们学完今天的内容,带大家彻底学习完JavaScript中的类型转换!再最后为大家解答就会一目了然!

数据类型的转换

基本数据类型的转换

在JavaScript中,类型转换是指将一个值从一种类型转换为另一种类型。我们知道,JavaScript分为两大数据类型!

原始数据类型引用类型

我们先讲原始数据类型的转换,因为nullundefined是特殊的原始值,它们没有构造函数,不能像对象一样使用构造函数来创建他们的实例,所以我们不予研究。ES6也新增了SymbolBigInt,其实他们类型转换基本机制相同,我们也不予研究。

我们在基本数据类型的转换当中研究:

  1. 原始值转布尔值
  2. 原始值转数字
  3. 原始值转字符串
  4. 原始值转对象

其实原始类型的转换还是很简单的,用一张图就可以为大家总结!

但是不用着急,我们一步一步走下去,带大家彻底理解!!

一、原始值转布尔值

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,

''nullundefinedNaN0'false'传过来为什么是false呢?

这是因为在 JavaScript 中,有一些值被视为"假值"(falsy values),它们在布尔上下文中被当作 false。以下值在布尔上下文当中都会被当作为false

  • undefined
  • null
  • 0
  • ""(空字符串)
  • false
  • NaN

对于NaN 和undefined 和 null 和 ""(空字符串),我觉得他们可以理解为直接调用Boolean()所以传过来的结果是false

其他所有值都被视为"真值",我们知道在布尔类型当中,0false,其他值为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,同样,布尔值转数字的话true1false0

三、原始值转字符串

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构造函数,也是返回一个空对象,而除了nullundefined,会转为空对象除外,对于其他的原始值都会成功地转为对象!

同时,我们其实还可以这样转对象:

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]

我们可以通过三种方式Stringa.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,再利用callthis显式绑定在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()重要重要重要!!!

我们可以看到,在NumbertoString的官方文档当中有一个ToPrimitive方法,我们先为大家解释!

这个方法是我们JavaScript内置引擎自己调用的方法!

Number的调用!

首先,如果传入的参数是一个基本类型的话,那么会直接返回!如果不是的话,会首先使用valueOf方法转换,如果得到原始值,则返回,如果得不到,那么会调用toString方法,如果得到原始值,则返回,如果还不行的话,就会报错了!

总结一下Number的调用!

ToPrimitive(obj,Number) ===> Number({}) 先用valueOf转换 发现转换不了,用toString 成功,再就是原始值转原始值 js自己调用的方法

  1. 如果obj是基本类型,直接返回
  2. 否则,调用valueOf 方法,如果得到原始值,则返回
  3. 否则, 调用toString方法,如果得到原始值,则返回
  4. 否则, 报错

toString的调用

在我们使用toString的时候,我们的内核引擎会先判断,传进来的值如果是基本类型,也是直接返回,否则会先调用toString方法,如果能得到原始值,就返回(注意!如果我们重写了toString方法,会导致访问不到Object下的toString方法),如果还不行,就会调用valueOf方法,如果得到原始值,则返回!如果还不行就会报错!

总结toString的调用

ToPrimitive(obj,toString) ===> String({})

  1. 如果obj是基本类型,直接返回
  2. 否则,调用 toString 方法,如果得到原始值,则返回 (假如,你再这个数据上重写了toString方法,导致访问不到Objcet下的toString方法)
  3. 否则, 调用 valueOf 方法,如果得到原始值,则返回
  4. 否则, 报错

我们再来看看官方文档!

其实,大家用着就会发现,似乎我们每次判断都不会用上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 == 11 == {}false == []二元==运算,它将会尝试去转换操作数到相同的类型,然后进行比较。

运算true == 11 == {}会将它们转换为数字进行比较!而false == []怎么会尝试将[]转换为布尔值进行运算!

最后答案揭晓!

js 复制代码
[]==![] //输出?true or false?

我们拿到我们的题目!首先,我们观察到这个语句中有两个运算符==!,我们要思考它们到底是怎样运算,我们就得知道它们的优先级!(运算符的优先级大家可以去查看一下),先告诉大家吧,!的运算优先级更高,所以我们先得知道![]是什么含义

取非,把它们绑在一起,我们知道==会尝试将操作数转换为相同的类型,我们也这样做!

这里也涉及到了一个抽象相等比较法!(es5.github.io/#x11.9.3)

![]转换为布尔是!true也就是false

于是我们的运算为[] == false,根据官方文档的抽象比较法的运算,==会尝试将两边转换为数字

所以最终的效果为:0 == 0

结果为true

学到这里了!大家有任何疑问和改正欢迎留言评论哦~

不知道大家看完有没有收获,真的很用心去写哦,大家仔细看看,阿远还是希望大家能学到一些知识!

点个赞鼓励支持一下吧!🌹🌹🌹

相关推荐
前端啊龙几秒前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js
一颗松鼠5 分钟前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
小远yyds25 分钟前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
阿伟来咯~1 小时前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端1 小时前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱1 小时前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai2 小时前
uniapp
前端·javascript·vue.js·uni-app
也无晴也无风雨2 小时前
在JS中, 0 == [0] 吗
开发语言·javascript
bysking2 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓3 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js