js-类型转换-详解

134 阅读7分钟

前言

javascript 和其他语言有所不同,没有直接定义和区分多种类型的变量,通常只是用var、let、const定义变量来区分变量的作用域,属于弱类型语言,而C语言、java等属于强类型语言,他们对于数据类型有明确的限制和区分,比如有int、float、double、string等类型。那么js执行引擎在执行过程中遇到变量、符号等,就会自动对他们进行转义和识别他们的类型再执行,这需要我们对js的类型转换规则有一个清晰的认识,让我们在看代码和写代码更加准确。

数据类型

要清楚js中发生的类型转换,就要知道在js引擎中数据到底可以区分为哪些类型:

原始数据类型: Number、String、Boolean、undefined、null

引用数据类型: Object、Function、Array (引用类型也都是对象,数组、函数、正则表达式等也都是对象)

以上是我们常用的数据类型,除此之外一还有Symbol、BigInt等数据类型,分析数据类型之间的转换我们只考虑这些常用的数据类型,相信小伙伴对于这些数据类型各自的意义用法已经了解,我们就不分析了

类型转换

原始类型之间转换

1> 原始值转布尔值

  • Number:当Number类型的值为 0 或 NaN 时,转换成布尔类型为false,其他Number转换为布尔为true
  • String:当String类型的值为空字符串时,转换成布尔类型为false,非空字符串转换布尔类型为true
  • Boolean:当Boolean类型值为false,转布尔仍为false,true转布尔仍为true
  • undefined:undefined转换成布尔类型为false
  • null:null转换成布尔类型为false
console.log(Boolean()); //false
console.log(Boolean(false)); //false
console.log(Boolean(true)); //true
console.log(Boolean(undefined)); //false
console.log(Boolean(null)); //false
console.log(Boolean(0)); //false
console.log(Boolean(-2)); //true
console.log(Boolean(NaN)); //false
console.log(Boolean('')); //false
console.log(Boolean('sdf')); //true
console.log(Boolean('0')); //true
console.log(Boolean('false')); //true

2> 原始值转数字

  • Number:空值转换成数字为0,NaN转换成数字仍为NaN,错误表达的数字转换成数字也是NaN
  • String:当String类型的值有等值的数字时,可以转换成该String对应相等的Number值,包括其他进制数也会转成十进制数;否则转换成数字为NaN
  • Boolean:当Bollean类型的值为false时,转换成Number类型为0,true转换成Number类型为1
  • undefined:undefined转换成Number类型为NaN
  • null:null转换成Number类型为0
console.log(Number());//0
console.log(Number(NaN)); //NaN
console.log(Number(1.234)); //1.234
console.log(Number(1.234.123)); //NaN
console.log(Number(undefined)); //NaN
console.log(Number(null));//0
console.log(Number(false)); //0
console.log(Number(true)); //1
console.log(Number('123')); //123
console.log(Number('123 + 1')); //NaN
console.log(Number('-00000123')); //-123
console.log(Number('+1.23')); //1.23
console.log(Number('%00000123')); //NaN
console.log(Number('0x11'));//17
console.log(Number(parseInt(10010,2))); //18
console.log(Number('123 123')); //NaN
console.log(Number('你好')); //NaN

3> 原始值转字符串

原始值转换成为字符串,都会将其值直接转换成字符串,内容不变

console.log(String()); //''
console.log(String(undefined)); //'undefined'
console.log(String(null)); //'null'
console.log(String(true)); //'true'
console.log(String(false)); //'false'
console.log(String(0)); //'0'
console.log(String(NaN)); //'NaN'
console.log(String(Infinity)); //'Infinity'

引用类型(对象)转原始类型

1> 对象转数字

会执行自带的ToPimitive(),主要有以下操作步骤:

1. 判断 obj 是否为基本类型,是则返回
2. 调用对象自带的 valueOf方法,如果能得到一个原始类型,则返回
3. 调用对象自带的toString方法,如果能得到一个原始类型,则返回
4. 报错

2> 对象转字符串

会执行自带的ToPimitive(),同样有以下操作步骤:

1. 判断 obj 是否为基本类型,是则返回
3. 调用对象自带的 valueOf方法,如果能得到一个原始类型,则返回
2. 调用对象自带的toString方法,如果能得到一个原始类型,则返回
4. 报错

3> 对象转布尔值

对象转换成布尔值,不管对象是否为空对象,得到的都是true

var a = 1
if({}){ //对象转布尔值为true,符合条件执行内部代码
    a = 2
}
console.log(a);//2

所以我们主要讨论考虑对象转换成数字和字符串,下面就主要举例详细分析一下什么情况下会运用到这几种引用类型转原始类型,以及具体如何转换

类型转换过程

1> 一元操作符 +

当 + 运算作为一元操作符使用时,会调用ToNumber()处理该值(相当于Number()),也就是将类型转换数字

此时遇到原始类型,则直接通过原始值转数字得到结果;

如果遇到引用类型:先执行对象转数字方法 ToPimitive() 的步骤,再调用ToNumber()方法转换成数字;

例1:+[]

遇到一元操作符 +,要将[]转换成数字,执行ToPimitive()步骤,先调用valueof()无法得到原始值类型,那么调用toString()方法得到空字符串'',再调用ToNumber()将空字符串转换成数字得到 0

image.png

例2:+['1','2','3']

同理,先调用valueof()无法得到原始值类型,那么调用toString()方法得'1,2,3',再调用ToNumber()将该字符串转换成数字得到 NaN

image.png

例3:+{}

同理,先调用valueof()无法得到原始值类型,那么调用toString()方法得'[object Object]',再调用ToNumber()将该字符串转换成数字得到 NaN

image.png

*注:{}打括号是因为浏览器会将其当成一个块级作用域

2> 二元操作符 +

计算 v1 + v2 时,有以下四个步骤:

1. lprim = toPrimitive(v1)  //对左边的变量调用toPrimitive()
2. rprim = toPrimitive(v2)  //对右边的变量调用toPrimitive()
3. 如果lprim 是字符串,则返回 ToString(lprim) 和 ToString(rprim) 的拼接结果  //因为字符串 + 其他原始类型还是字符串,即出现字符串就都转化为字符串再拼接
4. 否则 ToNumber(lprim) + ToNumber(rprim)

例1: null + 1

按照上面的步骤,两边调用toPrimitive(),两边都是基本类型(原始值),所以直接调用ToNumber(),null转换成数字为0,所以结果为1

image.png

例2: [] + []

两边都是引用类型,调用toPrimitive(),得到两个空字符串'',拼接后仍是''

image.png

例3: [] + {}

两边都是引用类型,调用toPrimitive(),左边得到'',右边得到'[object Object]',拼接都得到'[object Object]'

image.png

3> 双等号 ==

双等号是判断等号两边的值是否相等,这里建议直接看官方文档更加完整,主要有以下十点规则:

image.png

翻译:(其中未定义就是undefined)(翻译不准确,所以建议看原文,里面单词还是比较基础哈!)

image.png

我也从中总结了几点类型不相等的比较重要的:

  1. 等号两边类型不相等,统一往Number类型转换
  2. 等号两边有引用类型,先通过toPrimitive()转换成原始类型,再转换成Number比较
undefined == undefined //true
null == null //true
undefined == null //true
NaN == NaN //false
true == true //true
({}) == ({}) //false

3> 三等号 ===

1. 类型要相等
2. 值也要相等

考点:

类型转换最难的部分就是引用类型转换和比较,需要对转换规则充分理解和记忆,也是面试的时候容易碰到的点,下面就是曾经的一道面试题,我们需要清晰地分析出转换过程:

[] == ![]  //判断
  1. 首先,遇到!,就要先将右边的数组对象转换成布尔类型,再取反,得到等号右边为false
  2. 再就是引用类型和原始值得抽象比较(==),那么等号左边调用toPrimitive()转换成原始类型,得到空字符串''
  3. 然后就是两个原始值类型比较,两边两用ToNumber()转换成数字,两边都是0
  4. 所以最后结果为true

总结

类型转换在现实开发中可能不是那么常用,但是同样是非常重要的知识点,需要我们清晰地认识和理解转换原理和规则,在遇到时才能注意到细节,清楚分析,得到结果,所以希望这些内容能够帮助到小伙伴