likes
comments
collection
share

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

作者站长头像
站长
· 阅读数 2

在JavaScript中,类型转换是将一个数据类型的值转换为另一个数据类型的过程。类型转换可以分为显式(强制)类型转换和隐式(自动)类型转换。 对于初学者来说,隐式转换是十分让人头疼的一个问题,不过不急本文将带你深度理清类型转换。

  • 显式类型转换是通过特定的方法或操作符来强制将一个数据类型转换为另一个数据类型。
  • 隐式类型转换是在运行时自动发生的类型转换,不需要明确的代码进行转换。JavaScript会根据上下文自动进行类型转换,以便进行操作或比较。

本文中的类型转换只包括6种类型:Number,Boolean,String,Object,Undefined,Null

面试题:

//请写出以下代码的运行结果
//解析在最后的隐式转化里
console.log(1,1=={}) 
console.log(2,false ==[])
console.log(3,1==!!{})
console.log(4,NaN==NaN)
console.log(5,[]==![]) 
console.log(6,[]==[]) 
console.log(7,{}=={})
//解析在文中二元运算符'+'里
console.log(1+'1');
console.log([]+[])
console.log([]+{})
console.log({}+{})

显式转换

我们把显式转化分为原始类型和引用类型的转化,因为后者在转化的时候比前者多一个步骤调用内部ToPrimitive方法

一、原始数据类型的转换

原始数据类型转换为布尔

console.log("1转化为布尔值:"+Boolean(1))

console.log('---------------------------------------');

console.log("-1转化为布尔值:"+Boolean(-1));

console.log('---------------------------------------');

console.log("0转化为布尔值:"+Boolean(0));

console.log('---------------------------------------');

console.log("null转化为布尔值:"+Boolean(null));

console.log('---------------------------------------');

console.log("undefined转化为布尔值:"+Boolean(undefined));

console.log('---------------------------------------');

console.log("字符串转化为布尔值:"+Boolean('hello world'));

console.log('---------------------------------------');

console.log("空字符串转化为布尔值:"+Boolean(''));

console.log('---------------------------------------');

console.log("空格转化为布尔值:"+Boolean(' '));

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

  • 通过Boolean()方法实现
  • 当nunmber类型转布尔类型时0为false其余均为true
  • 当null,undefined转布尔类型值为false
  • 当字符串转布尔类型时,只要字符串不为空,值为true,空字符串值为false

原始数据类型转换为Number

//原始数据类型转Number
console.log('字符串123转数字'+Number('123'));
console.log('---------------------------------------');
console.log('字符串123.123转数字'+Number('123.123'));
console.log('---------------------------------------');
console.log('字符串003.123转数字'+Number('003.123'));
console.log('---------------------------------------');
console.log('普通字符串hello'+Number('hello'));
console.log('---------------------------------------');
console.log('null转数字'+Number(null));
console.log('---------------------------------------');
console.log('undefined转数字'+Number(undefined));
console.log('---------------------------------------');
console.log('布尔值true转数字'+Number(true));
console.log('---------------------------------------');
console.log('布尔值false转数字'+Number(false));

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

  • 通过Number()方法实现
  • 字符串转number类型时,字符串内容表示的为合法数字时才能转化为number
  • 字符串转number类型时,字符串内容表示数字前有0,会把0忽视掉
  • 字符串转number类型时,字符串内容并不是合法数字时,会得到NaN表示无法表示大小的值
  • null,undefined转化number类型值为0
  • 布尔值转number类型,true转化为1,false转化为0

原始数据类型转化为字符串

console.log('123转字符串'+String(123));
console.log('---------------------------------------');
console.log('NaN转字符串'+String(NaN));
console.log('---------------------------------------');
console.log('-infinity转字符串'+String(-Infinity));
console.log('---------------------------------------');
console.log('null转字符串'+String(null));
console.log('---------------------------------------');
console.log('undefined转字符串'+String(undefined));

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

  • 原始数据类型转化字符串就是返回你输入在括号里面的字符
  • 两种写法调用原型链上的.toString()或者调用构造函数String()

原始数据类型转化为引用数据类型

let a = new Number(1234)
console.log(a)
console.log(Object(123));

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

  • 通过Object()构造函数
  • 直接通过封装类的构造函数创建对应的封装类对象

二、引用类型转化

虽然能将引用类型赋值为undefined和null,但是引用数据类型并不能转化为undefined,null类型 在JavaScript中,对象本身不能直接转化为undefined类型。

Undefined类型是JavaScript中的一个原始数据类型,表示未定义或未初始化的值。然而,在实际编程中,你可以将对象的属性或变量赋值为undefined来表示未定义或未初始化的状态。

例如:

let obj = { key: 'value' };
obj = undefined; // 将对象赋值为undefined

// 或者
let obj = { key: 'value' };
obj.key = undefined; // 将对象的属性赋值为undefined

在JavaScript中,对象可以被赋值为null来表示空对象。Null类型也是JavaScript中的一个原始数据类型,表示一个空或无效的对象引用。因此,将对象赋值为null等同于将其清空。

例如:

let obj = { key: 'value' };
obj = null; // 将对象赋值为null

// 或者
let obj = { key: 'value' };
obj.key = null; // 将对象的属性赋值为null

在上述例子中,obj被赋值为null,这样就可以表示对象为空。需要注意的是,这并不是将对象本身转化为null类型,而是将对象引用指向了null。 在上述例子中,obj被赋值为undefined,这样就可以表示对象的未定义状态。但需要注意的是,这并不是将对象本身转化为undefined类型,而是将对象引用指向了undefined。

引用类型转布尔

规定引用类型转化为布尔值均为true

function a(){}
console.log(Boolean(a));
console.log(Boolean({}));
console.log(Boolean([]))

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

引用类型转String

当使用toString或者是String()方法转化引用类型为字符串时,包括下面使用Number()将引用类型转Number类型时都会先内部调用ToPrimitive方法

ToPrimitive方法

在 JavaScript 中,ToPrimitive 是一个内部方法,用于将一个值转换为原始值。在很多情况下,当 JavaScript 需要对一个非原始值执行操作时,会首先调用 ToPrimitive 方法来尝试将其转换为原始值。 ToPrimitive 方法接受一个参数 hint,可以是 "number" 或 "string" 中的任意一个。这个参数表示希望将值转换为数字还是字符串类型。

当想要转化为String类型时,hint为String 调用ToPrimitive(obj,String)

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

toString方法

这个方法是写在Object的原型上,所以所有的数据类型都能够访问除了undefined和null,以及Object.create(null)创建的对象

规则:

  1. 对象调用:{}.toSring 返回由"[Object" 和 类型名和"]"组成的字符串
  2. 数组调用:[].toString 返回由数组内部元素以逗号拼接的字符串
  3. 原始数据类型 xx.toString 直接返回字符串变量(可参考上面的原始数据类型转化)

valueOf方法

这个方法也是写在是写在Object的原型上,所以所有的数据类型都能够访问除了undefined和null,以及Object.create(null)创建的对象

let str = new String('hello world')
let num = new Number(123)
let boo = new Boolean(true)
let obj = {
    a:2,
    b:()=>{

    }
}
function foo(){

}
let arr = [1,2,3,4,5,6,7,8,9]
console.log(str.valueOf());
console.log(num.valueOf());
console.log(boo.valueOf());
console.log(obj.valueOf());
console.log(arr.valueOf());
console.log(foo.valueOf());

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

  • 对于原始数据类型的封装类,调用valueOf()会返回对应的原始数据类型的值
  • 对于对象valueOf会直接返回该对象
let a ={}
let arr = []
let arr1= [1,2,3,4]
function foo(){}
console.log(a.toString(),arr.toString(),arr1.toString(),foo.toString());

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

那么回到引用类型转String类型,会先调用内部方法ToPrimitive(obj,String)

  1. 首先 调用toString()方法,得到字符串[Object,类型] (类型即为引用对象类型),为原始值返回给String()方法
  2. String()方法得到ToPrimitive返回值字符串后,因为传入值为字符串所以直接返回该字符串

引用类型转Number

当想要转化为Number类型时,hint为Number, 调用ToPrimitive(obj,Number)

  1. 如果obj是基本类型,直接返回
  2. 否则,调用valueOf方法如果得到原始值则返回
  3. 否则,调用tostring方法,如果得到原始值则返回
  4. 否则报错
  1. 将引用类型转化为原始值 首先调用valueOf方法我们知道引用类型调用之后还是直接返回引用类型,不是原始值
  2. 再调用toString()方法,得到字符串[Object,类型] (类型即为引用对象类型),为原始值返回给Number()方法
  3. 也就是说传了一个字符串给Number()方法,在上面原始类型转Number中知道字符串内容并不是一个合法的数字时会返回NaN

所以当引用数据类型转Number时都会得到NaN

let a ={}
let arr = []
let arr1= [1,2,3,4]
function foo(){}
console.log(Number(a),Number(arr),Number(arr1),Number(foo))

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

  • a转化为[Object,Object]再转为为NaN
  • arr转化为'',在转化为0
  • arr1转化为'1,2,3,4',在转化为NaN
  • foo转化为[Object,Function],再转化为NaN 引用类型转Number类型,会先调用内部方法ToPrimitive(obj,Number)

隐式转换

一元运算符'+'

  • 会将后面接的变量转化为Number类型
console.log(+'23',+'123a',+null,+undefined,+'',+{},+[],+[1,2,3]);

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

  • '23',字符串内容为合法数字,可以转化为对应内容的数字
  • '123a',字符串内容非法数字,返回NaN,表示无法表示大小
  • null,undefined,返回0
  • {},空对象转Number类型,参考上面引用类型转Number,得到NaN
  • [],[1,2,3]的区别,因为在调用ToPrimitive方法时会将其转化为字符串,[]转为为空字符串'',[1,2,3]转化为'1,2,3',再给Number()处理,所以前者结果为0,后者为NaN

二元运算符'+'

  1. 当加号两边有一个为字符串,则按字符串进行拼接
  2. 否则转到number进行计算

注意

2.的规则中补充,如果转化为Number的过程中变成了字符串就按照1.来运算

console.log(1+'1');
console.log([]+[])
console.log([]+{})
console.log({}+{})

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

  • 1+'1'存在字符串按照字符串拼接
  • []+[],数组转Number过程中会变成中间体空字符串''停下执行1.中的字符串拼接
  • []+{},空字符''和字符串[Object,Object]拼接
  • {}+{},字符串[Object,Object]和字符串[Object,Object]拼接

二元运算符'=='

对于计算机来说数字的运算是最快的,同样引擎在执行==运算时,会将两边的变量往Number类型转换

注意

  • 但是在两边都是引用数据类型的时候,并不会触发隐式转换,而是直接比较二者的引用地址
  • 等式两边只要有一边出现NaN等式结果就是false
console.log(1,1=={});
console.log(2,false ==[]);
console.log(3,1==!!{});
console.log(4,NaN==NaN);
console.log(5,[]==![])
console.log(6,[]==[])
console.log(7,{}=={});

JS中显式隐式类型转换,你真的弄懂了吗(含多道面试题)

  • 1.{}转化为NaN,出现NaN,结果即为false
  • 2.[]转化为0,false转化也为0,相等
  • 3.{}转化为布尔值对象转布尔一定为true,双重否定值不变,true转化为Number为1,等式成立
  • 4.两边都为NaN但是只要出现NaN等式就为false
  • 5.右边[]先被转化为true再被否定为false再转为0,左边[]转化为0,等式成立
  • 6.两边均为引用数据类型,比较地址,等式不成立
  • 7.同上,等式不成立

JS官方文档

官方文档:es5.github.io/

ToPrimitive方法: es5.github.io/#x9.1