JavaScript隐式转换

JavaScript中有两类数据类型:原始类型和对象类型,原始类型也叫基本数据类型,包括:Undefined、Null、String、Number、Boolean、Symbol(es6新推出的,暂不考虑);对象类型:object。

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

隐式转换中主要涉及到三种转换:

1.将数值转换为原始值,ToPrimitive();

2.将数值转化为数字,ToNumber();

3.将数值转换为字符串,ToString().

这里补充一下通过ToPrimitive()将值转化为原始值

js引擎内部的抽象操作ToPrimitive有着这样的签名:

ToPrimitive(input, PreferredType?)

input是输入的值,即要转换的对象,必选;

preferedType是期望转换的基本类型,他可以是字符串,也可以是数字。选填,默认为number;

他只是一个转换标志,转化后的结果并不一定是这个参数值的类型,但是转换结果一定是一个原始值(或者报错)。

对于Date求原始值比较特殊,PreferredType是String,其他Object对象均为Number。

基本类型的转换

1、字符串加数字,数字就会转成字符串。数字加数字或字符串加字符串不需要转换。

在加法的过程中,首先把等号左右两边进行了求原值ToPrimitive()操作,如果有两个或多个原始值,只要其中有一个是String类型,就把两个或多个原始值都进行转化字符串toString()操作,进行字符串拼接;否则把两个或多个原始值都进行转化数字toNumber()操作,进行数字相加。

var a = 1 + 2 + '3';
console.log(a, typeof a); // '33' string
var b = 1 + 2 + 3;
console.log(b, typeof b); // 6 number

2.数字减字符串,字符串转成数字。如果字符串不是纯数字就会转成NaN。字符串减数字也一样。两个字符串相减也先转成数字。

// -
10 - '20'    //-10
10 - 'one'   //NaN
10 - '100a'  //NaN

3.乘,除,大于,小于跟减的转换也是一样。

 // *
10*'20'      //200
'10'*'20'    //200
// /
20/'10'      //2
'20'/'10'    //2
'20'/'one' //NaN

这里补充一个关于==的隐式转换

1.undefined等于null

2.字符串和数字比较时,字符串转数字

3.数字和布尔比较时,布尔转数字

4.字符串和布尔比较时,两者转数字

// ==
undefined == null;    //true
'0' == 0;          //true,字符串转数字
0 == false;           //true,布尔转数字
'0' == false;    //true,两者转数字

引用数据类型的转换

基本类型间的比较相对简单。引用类型和基本类型的比较就相对复杂一些,先要把引用类型转成基本类型,再按上述的方法比较。 往下介绍PreferredType转换策略

preferredType转换策略分为两种情况

(1)如果PreferredType被标记为Number,会进行下面的操作流程来转换输入的值。

1、如果输入的值已经是一个原始值,则直接返回它

2、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法, 如果valueOf()方法的返回值是一个原始值,则返回这个原始值。

3、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。

4、否则,抛出TypeError异常。

(2)如果PreferredType被标记为String,会进行下面的操作流程来转换输入的值。

1、如果输入的值已经是一个原始值,则直接返回它

2、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。

3、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法, 如果valueOf()方法的返回值是一个原始值,则返回这个原始值。

4、否则,抛出TypeError异常。

 需要注意的是:PreferredType的值会按照这样的规则来自动设置:

1、该对象为Date类型,则PreferredType被设置为String

2、否则,PreferredType被设置为Number

下面通过三个案例来感受一下

 [ ] + [ ] //" "

 进行ToPrimitive,两个都是Array对象,不是Date对象,所以以Number为转换标准,所以先调用valueOf(),结果还是[ ],不是原始值,所以继续调用toString(),结果是“”(空字符串)原始值,将“”返回。第二个[ ]过程是相同的,返回“”。加号两边结果都是String类型,所以进行字符串拼接,结果是“”。

[] + {}    // "[object Object]"

 进行ToPrimitive,依然是以Number为转换标准。 [ ]的结果是“”。 { }先调用valueOf(),结果是{ },不是原始值,所以继续调用toString(),结果是“[object Object]”,是原始值,将“[object Object]”返回。 加号两边结果都是String类型,所以进行字符串拼接,结果是“[object Object]”。

{} + [] // 0

 

这道题按照上一题的步骤,讲道理的话,结果应该还是“[object Object]”,但结果却出人意料——显示的答案是0! 这是什么原因呢?js解释器会将开头的 {} 看作一个代码块,而不是一个js对象;原来{ } + [ ]被解析成了

{ };+[ ],前面是一个空代码块被略过,剩下+[ ]就成了一元运算。[ ]的原值是””, 将””转化成Number结果是0。

{} + {} // "[object Object][object Object]"

 在金丝雀版本的chrome浏览器和node中,结果符合预期。 结果是”object Object”。 在普通版本的chrome浏览器中结果是NaN。 这是为什么呢?原因是在node中会将以“{”开始,“}”结束的语句外面包裹一层( ),就变成了({ } + { }),结果就符合预期。而普通版本的chrome依然会解析成{};+{},结果就变成了NaN

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值