类型转换魔法:JavaScript中的数据类型大变身

359 阅读7分钟

前言

JavaScript的广阔天地里,类型转换是一个既基础又深奥的课题。它如同一位默默无闻的幕后工作者,悄然影响着代码的执行流程和结果。无论是初学者还是资深开发者,都难免会在与类型转换的交锋中遇到困惑和挑战。但正是这份复杂性,赋予了JavaScript灵活而强大的表达能力。本文旨在深入剖析JavaScript的类型转换机制,揭示其背后的原理和规则。通过理解和掌握这些类型转换的奥秘,我们将能够编写出更加准确、高效和健壮的代码,从而在JavaScript的编程之路上迈出更加坚实的步伐。

==vs===

console.log('1'==1);
console.log('1'===1);

看一下这两行代码,猜一猜它的执行结果

87.png

可以看到这两个代码执行结果是不相等的

所以我们要知道===; 叫全等,不会进行隐式类型转换,意味着会判断值和类型是否相等,==;会进行隐式类型转换,所有只会判断值是否相等

类型转换

我们来看看下面这道大厂面试题

console.log([]==[]);
console.log([]==![]);

判断这两段代码的输出结果,第一个我们都知道引用类型比较的是地址值,而不存在两个地址值完全相等的对象,因此第一行代码输出的肯定是false,那为什么加个!就相等了呢,我们都知道!在js中只是一个相反符号,这能有什么作用呢,其中就涉及到了类型转换,而面试官想问的就是你对类型转换的理解。读完这篇文章,你就能对类型转换有一个很深的理解了

原始类型之间的转换

我们先来想一下什么样子的代码进行与原始类型之间的转换,比如刚刚那==就是,还有就是字符串和数字的相加

1 + '1'=='11'

像这行代码,它会先把数字1转换为字符串'1',然后再拿两个字符串相加,就得到了'11',

'1' + true = '1true'

那字符串加布尔类型呢,要知道相加肯定要先转换为同一类型,布尔和布尔肯定是不能相加的,那会都转换为数字吗,也不是,布尔类型会先转换为字符串,然后再和字符串相加

我们知道一共有七种原始类型(Number,String,Boolean,bigInt,undifined,Null,Symbol()),而后面四种都不会有其它类型转为它们的情况,所以原始类型转换只有三种情况,转布尔,转字符串,转数字。

转布尔

console.log(Boolean(true));
console.log(Boolean(undefined));
console.log(Boolean(null));
console.log(Boolean(-100));
console.log(Boolean(0));
console.log(Boolean(NaN));
console.log(Boolean('hello'));
console.log(Boolean(''));

我们将各种类型转为布尔看看都会转换为什么

88.png 可以看到布尔转布尔就是相当于没转,而有效数字转为布尔都为true,0false,NaNfalse,有字符的字符串转为布尔为true,空字符串为false,nullundefinedfalse。这些就是转为布尔的全部规则了

转数字

console.log(Number(1));

console.log(Number('0'));

console.log(Number(undefined));

console.log(Number(null));

console.log(Number('hello'));

我们看看其它类型转数字是怎么样的

89.png 如果传入的是一个数字,其实它是不会转换的,而是将数字直接输出,如果是数字字符串,那么就会转换为对应的数字,undefined会转为NaN,而null会转换为0,如果是一个字符串,那么就不知道转换为什么数字,于是就会转换为未知数字NaN

转字符串

原始类型转字符串是最简单粗暴的,就是用一对引号引起来。

对象转为原始值

对象转换为字符串

let a ={}
console.log(String(a));

我们将对象转换为字符串是怎么样的,看看输出结果

90.png 为什么是这样的呢,其实在将对象转换为字符串的时候,v8引擎会先调用ToString方法,解决不了,然后就会使用ToPrimitive()方法,然后使用对象的toString方法转换为字符串。然后对象转字符串的方法在Object上,这是toString()方法执行的官方文档

84.png 这个文档表示的是当 Object.pritotype.toString.call()被执行的时候会干的几步操作,如果是undefined的话,那就直接返回[object Undefined],如果是null,那就返回[object Null]

其它的,设0为调用To0bject 的结果,将this 值作为参数传递ToObject(this)class为0的[[Class]]内部属性的值。[[Class]]js内部的属性,只有v8能用,可以直接读取变量的类型,最后返回由“[object ”、class 和 “]” 三块拼接的结果。

91.png 那为什么数组转为字符串是这样的,我们看了官方文档,如果是用的Object上的toString方法,格式就绝对不是这样的。那到底是为什么呢,其实是在数组的构造函数上重写了这个方法,而在数组上的toString方法就会返回由数组中元素由逗号分隔的字符串。

92.png 除了对象和数组,其它引用类型用toString转换为字符串都是直接返回 xx 的字符串字面量。

对象转布尔

93.png 在官方文档上就一条,true,无论什么对象转为布尔都是true

对象转数字

方法Number(obj)

过程 :To Number({}) //ToPrimitive({})

转数字会调用To Number({}) ,然后调用然后对象不能直接转为数字,就会使用ToPrimitive({}),转为原始类型最后再通过原始类型转换又再次变为数字

ToPrimitive({})

ToPrimitive(obj,String)

-如果obj是原始类型,直接返回 -否则调用toString()方法,如果得到原始类型则返回 -否则调用valueOf()方法,如果得到原始类型则返回 -否则报错

ToPrimitive(obj,Number)

-如果obj是原始类型,直接返回 -否则调用valueOf()方法,如果得到原始类型则返回 -否则调用toString()方法,如果得到原始类型则返回 -否则报错

隐式类型转换场景

1.四则运算:+ - * / %

2.判断语句 if while == > < >= <= !=

一元运算符 +

转数字类型

二元运算符 +

val1 + val2

lprim = ToPrimitive(val1)

rprim = ToPrimitive(val2)

如果 lprim或者rprim是字符串,另一个值直接被ToString()

  • 否则,都处理为数字,返回ToNumber(lprim) + ToNumber(rprim)应用加法运算的结果

==

如果类型相同,就比较值。 如果是null和undifined,那么返回true

其它的,如果是类型不同的比较,都是先转为数字再进行比较

最后我们再来看这道大厂面试题

console.log([]==[]);
console.log([]==![]);

为什么加个!就是true了呢,我们来类型转换分析一下,首先由于前面加了一个,那么就会使[]转换为布尔类型,前面我们提到过,所有引用类型转为布尔类型都会转为true,这是官方制定的规则,然后被变为false,接下来就是两个不同类型用==进行比较了,那么我们就要先把它们转换为数字再比较,false转为数字就是0,而[]需要用toString转换为字符串,也就会变成空字符串'',然后再将字符串转为数字,空字符串转为数字就是0,最后v8就是将它们变成了0==0,当然返回的就是ture

看懂这些,那么你就已经掌握了js中类型转换这个知识点了。

结语

我们深入了解了JavaScript中的类型转换机制,学习了如何将原始类型和对象转换为字符串、数字和布尔值,并掌握了在特定场景下的类型转换规则。这不仅有助于我们更好地理解JavaScript的比较和运算行为,也为我们解决面试和实际开发中的类型转换问题提供了有力的武器。类型转换是JavaScript中的一个重要且复杂的概念,但通过不断学习和实践,我们可以逐渐掌握它,从而写出更加健壮和可靠的代码。