关于js中的隐式类型转换

本文详细探讨了JavaScript中的隐式类型转换,包括在运算符和语句中的表现,如+、==运算符的转换规则,以及在if、while语句中的布尔转换。同时,文章列举了常见的陷阱,如NaN的误判、复杂数据类型的转换问题,并提供了避免陷阱的方法。通过对隐式类型转换的理解,有助于避免JavaScript编程中的潜在错误。
摘要由CSDN通过智能技术生成
  • 2021-01-07
    刚爬出数据类型判断,又进了隐式类型转换的大坑,那就根据日常会碰到的问题简单写一下吧。
  • 2021-01-08
    昨天写到一半让朋友们拉去云喝酒了,今天继续

一、开始

我最早接触到隐式类型转换是因为看到这么一段代码:

const a = {
	i:1,
	toString: function () {
 		return a.i++;
	}
}
if (a == 1 && a == 2 && a == 3) {
	console.log('hello world!');
}

当时我百思不得其解,为什么这个 if 语句可以成立,还执行了打印语句。也就是因为这个题目,我慢慢了解到了隐式类型转换这个问题。



二、为什么会出现隐式类型转换

  • 在js中,当运算符在运算时,如果两边数据不统一,CPU就无法计算,这时我们编译器会自动将运算符两边的数据做一个数据类型转换,转成一样的数据类型再计算
  • 这种无需程序员手动转换,而由编译器自动转换的方式就称为隐式转换


三、运算符中的隐式类型转换


在实际应用中,最常见的就是+或者==这种运算符导致的隐式类型转换,在操作过程中,系统没办法把不同类型的数据进行运算,所以他会自动进行类型转换。

运算符中的隐式类型转换主要分为以下几种情况:


1. 转换为数字类型

+、-、*、/、++、–、+=、-=、>、<、>=、<=、==、!= 这些运算中,系统都会将值先转换为数字类型再进行计算或比较。


加号运算符( + )可以把任何数据类型转换为数字,转换规则与 Number() 方法相同。

Null、Undefined 和 false在与数字的计算中折算为0,true 折算为1。
undefined会被转换为 NaN。
NaN在算术运算符中遇到任何值进行比较结果都为NaN。

console.log(1+'true');		//'1true'
console.log(1+true);		//2
console.log(1+null);		//1
console.log(1+undefined);		//NaN

可以用加号运算符很方便的把其他类型的值转换为数字类型。

console.log(+true); 		//1
console.log(+undefined); 	//NaN
console.log(+"123"); 		//123
console.log(+"string"); 	//NaN

除了加号运算符,也可以使用 a - 0 的形式,将数据类型转换为数字。

console.log(11-'5'); 		//6
console.log('11'-'5');		//6
console.log(-null);			//-0
console.log(true - 0); 		//1
console.log(null - 0); 		//0
console.log("123" - 0); 	//123
console.log("" - 0); 		//0
console.log([999] - 0); 	//999
console.log([2] - [1]); 	//1

比较运算符(= =),== 不同于===,故也存在隐式转换。
比较运算符会把其他数据类型转换number数据类型后再比较。

在javascript中有两种特殊情况无视规则:

  1. null == undefined;
  2. NaN和谁都不相等,包括他自己
console.log(undefined==null);		//true

其他值类型进行比较的时候都会将运算数转换为数字

console.log("3"==3);		//true
console.log("1"==true);		//true
console.log(false == 0);		//true
console.log(false == "");       //true
console.log(NaN == NaN);        //false
console.log(undefined == null);     //true

比较运算符(>、<)中也存在隐式类型转换。

console.log("2" > 10);      //false
console.log("a" > 10);      //false
console.log(10 > "a");		//false

但是最好不要这样比较,因为会非常容易翻车

比较运算符的规则是这样的:

  • 比较运算符的一边是字符串的时候,会调用 Number() 方法把字符串转换成数字在进行比较
  • 当关系运算符两边都是字符串的时候,此时同时转成number然后比较关系。
    重点:此时并不是按照Number()的形式转成数字,而是按照字符串对应的unicode编码来转成数字,使用 字符串.charCodeAt(字符下标,默认为0) 方法可以查看字符的unicode编码。
  • 布尔值和数字比较时,会把布尔值通过 Number() 转成数字再进行比较,true转成 1,false 转成 0;
  • 字符串和布尔值比较时,会把字符串和布尔值都通过 Number() 转成数字再进行比较
console.log("2" > "10");        //true    

在这里面,‘2’ 的 Unicode 编码是50,'10’的 Unicode 编码是49,所以返回的值为 true。



2. 转换为字符串类型

+运算符既可数字相加,也可以字符串相加。

console.log(1+'2');		//12
console.log("12" + "3"); 		//"123"
console.log("12" + 3); 		//"123"
console.log(12+ 3); 		//15
console.log(1+'2'+ 3); 		//'123'

根据 ES5 规范,如果某个操作数是字符串或者能够转换为字符串的话,+ 将进行拼接操作。
其中,"能够转换为字符串"的操作主要是针对对象而言,当某个操作数是对象的时候,会首先检查该对象能否通过 valueOf() 方法返回基本类型值,如果不能,就转而调用 toString() 方法。
通过以上两个步骤,如果可以得到字符串,那么+ 也将进行拼接操作,否则执行数字加法。

console.log("" + 1);		//"1"
console.log("" + true);		//"true"
console.log("" + null);		//"null"
console.log("" + [3, 4]);		//"3,4"
console.log("" + "string");		//"string"
console.log("" + undefined);		//"undefined"

在进行拼接操作的时候,也会将另一个操作数隐式转换为字符串。
这个隐式转换和使用 String() 方法之间有一个细微差别需要注意:
隐式转换会对操作数首先调用 valueOf() 方法,然后通过 toString() 方法将返回值转换为字符串,而使用 String() 方法则是直接调用 ToString()。

var o = {
    valueOf: function() {
        return 11;
    },
    toString: function() {
        return 22;
    }
};
console.log(o + ""); //输出:"11"
console.log(String(o)); //输出:"22"


3. 转换为布尔类型

逻辑非运算符( ! )可以把任何数据类型转换为布尔值,转换规则与 Boolean() 方法相同,一般会连续用两个叹号( !! ),因为第二个叹号会将结果反转回原值。

  • 0、-0、NaN、undefined、null、空字符串、false、document.all() 用逻辑非运算符的结果为false。
  • 除了以上八种情况之外,所有数据都会得到 true 。
console.log(!!0); 		//false
console.log(!!-0); 		//false
console.log(!!""); 		//false
console.log(!![]); 		//true
console.log(!!{}); 		//true
console.log(!!null); 		//false
console.log(!!false); 		//false
console.log(!!NaN); 		//false
console.log(!!undefined); 		//false


四、语句中的隐式类型转换


1. if 语句

if 语句会将值隐式转换为Boolean类型

var obj = {name:'jack'} 
if(obj){ 
    //do something..
} 


2. while 语句

while 语句和 if 语句的作用相同,将值隐式转换为Boolean类型

var obj = {name:'jack'} 
while(obj){ 
    //do something..
} 


五、常见问题(当心踩坑)


1. NaN的判断错误

隐式类型转换有时候是会隐藏一些错误的,比如,null会转换成0,undefined会转换成NaN。需要注意的是,NaN和NaN是不相等的

console.log(NaN === NaN); 		//false

JavaScript本身提供判断某个值是否为NaN的方法isNaN(),但是这个方法并不是非常准确,因为在调用这个方法的时候,他会有一个隐式类型转换的动作将这个值转换为数字类型,这样就会导致把原本不是NaN的值转换成NaN。

console.log(isNaN({}));		//true
console.log(isNaN("foo"));		//true
console.log(isNaN(undefined));		//true

这个问题也非常好解决,因为NaN是一个特殊的值,只有他自己不等于自己,我们利用这一点,可以自己写一个方法来判断:

function isRealNaN(x) {
    return x !== x;
}
console.log(isRealNaN(NaN));		//true
console.log(isRealNaN({}));		//false
console.log(isRealNaN("foo"));		//false
console.log(isRealNaN(undefined));		//false


2. 复杂数据类型的隐式转换

复杂数据类型在隐式转换时的顺序如下:

  1. 先试用 valueOf() 方法获取其原始值,如果原始值不是 number 类型,则使用 toString() 方法转换成 string 类型。
  2. 将 string 类型转换成 number 类型进行运算。
console.log([1,2]=='1,2');		//true

将 [1,2] 用 valueOf() 取其原始值,发现不是数字类型,转换成 string 类型之后,发现与 ‘1,2’ 相等,所以返回 true。

var a = {};
console.log(a=="[object Object]");		//true

这些问题都是因为==的隐式类型转换造成的。

console.log({} == 0);        //false
console.log({} == []);        //false

另外,空数组的toString()方法会得到空字符串,而空对象的toString()方法会得到字符串[object Object]

console.log([] == 0);       //true  

[] 通过同String()转成空字符串,再通过Number()转成0。



3. 逻辑非隐式转换与关系运算符隐式转换搞混淆

逻辑非运算符和关系运算符的原理上面都讲过了,但是放在一起用的话非常非常容易踩坑:

console.log([]==0);			//true
console.log(![]==0);		//true

[] 与 0比较:

  • [].valueOf().toString() 得到空字符串
  • Number("") == 0 成立

![] 与 0比较:

  • 逻辑非优先级高于关系运算符,![] = false (空数组转布尔得到true,然后取反得到false)
  • false == 0 成立
console.log([]==[]);		//false
console.log([]==![]);		//true

[] 与 []比较:

  • 引用类型数据存在堆内存中,栈内存中存储的是地址,所以他们的结果是false。
    (我自己也不是很懂,看到别的大神是这么解释的,先抄下来吧…)

[] 与 ![]比较:

  • [].valueOf().toString() 得到空字符串 “”
  • ![] = false
  • Number("") == Number(false) 成立 都是0
console.log({}=={});		//false
console.log({}==!{});		//false

{} 与 {}比较:

  • 引用类型数据存在堆内存中,栈内存中存储的是地址,所以他们的结果是false

{} 与 !{}比较:

  • {}.valueOf().toString() 得到字符串’[object Object]’
  • !{} = false
  • Number(’[object Object]’) == Number(false) 不成立,因为转换到最后 是NaN 和 0比较,所以结果为 false




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值