面试题:[]==![] 结果是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

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

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

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

相关推荐
Jet_closer_burning1 分钟前
Vue2 和 Vue3 的响应式原理对比
前端·javascript·vue.js·html
xing251629 分钟前
pytest-html
前端·html·pytest
茂茂在长安39 分钟前
Linux 命令大全完整版(11)
java·linux·运维·服务器·前端·centos
Violet51540 分钟前
ECMAScript规范解读——this的判定
javascript
知识分享小能手1 小时前
Html5学习教程,从入门到精通,HTML5 简介语法知识点及案例代码(1)
开发语言·前端·javascript·学习·前端框架·html·html5
IT、木易1 小时前
大白话React第二章深入理解阶段
前端·javascript·react.js
晚安7201 小时前
Ajax相关
前端·javascript·ajax
图书馆钉子户1 小时前
怎么使用ajax实现局部刷新
前端·ajax·okhttp
bin91532 小时前
DeepSeek 助力 Vue 开发:打造丝滑的单选按钮(Radio Button)
前端·javascript·vue.js·ecmascript·deepseek
qianmoQ2 小时前
第五章:工程化实践 - 第五节 - Tailwind CSS 常见问题解决方案
前端·css