注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

前端开发那点事儿

冒犯之处,敬请谅解。

 
 
 

日志

 
 
 
 

聊一聊 JS 中的『隐式类型转换』  

2016-04-05 11:12:12|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
原文  http://blog.sqrtthree.com/2016/01/23/implicit-type-conversion/

类型转换还不行?还非得隐式?这是什么高级玩意?

废话不多说,我们先上一盘:chestnut:,额,不对,先看一个例子吧。

3 + true

实际上在大多数编程语言中,都会认为上面这个表达式是错误的。因为布尔表达式与算术运算是不兼容的。尤其是在静态语言中,甚至不会被运行运行。即使是动态语言中,通常虽然可以让程序运行,但是会抛出一个异常。

然而,然而, Javascript 不仅运行程序能够正常运行,而且还会顺利地产生结果 4。Javascript 真的是对类型错误出奇的宽容啊。看起来很像是一件好事对不对?

基本上,在 Javascript 中,只有在一些极少数情况下才会因为类型错误而抛出一个异常。诸如: 调用非函数对象或者获取 null / undefined 的属性时。

但是在大多数情况下,Javascript 都是不会抛出异常的。这个『小婊砸』反而按照多种多样的转换协议偷偷的强制转换为她期望的值。诺,你看,还花样转换呢,真会玩嘛。这就是所谓的『隐式类型转换』。

那么,上面那个例子中,究竟是发生了什么样的转换方式呢?

首先,Javascript 这个『小婊砸』在遇到算数运算符( -*/% )的时候会在运算之前将参与运算的双方转换成数字。

那么问题又来了, true 怎么就转换成数字了呢?实际上我们通过 Number(true) 就可以看到, true 转换为数字之后就是为 1,相反, false 转换为数字之后就对应为 0。

细心的你可能发现我在上面并没有提到 + 运算符,那是因为它更复杂。因为它既承担着数字相加,又肩负着字符串连接操作的重任。具体的行为取决于参数的类型。

但是,如果一个数字和一个字符串相加,会碰撞出什么样的火花呢?

显然 Javascript 这个『小婊砸』更偏爱字符串多一点,她会将数字( toString() )转换为字符串,然后执行字符串连接操作。

例如:

"1" + 2;    // "12"
1 + "2";    // "12"

但是,注意,Javascript 对操作顺序非常敏感,以至于会发生这样的事情:

1 + 2 + "3";    // "33"

因为加法运算是自左向右的,因此它等同于下面的表达式:

(1 + 2) + "3";    // "33"

再来看这一个例子:

if (1 == true) {
    alert("true");
} else {
    alert("false");
}

相信你一定轻松的猜到了结果对不对?

但是,哼,你以为我的问题会这么简单么?那岂不是太小看你了。

我们都知道,Javascript 中,数字 0 为假, 非0 均为真, 那么我想问的是,在上面的条件语句中,到底是 1 被隐式类型转换了呢还是 true 被隐式类型转换了呢?

实际上在条件判断运算 == 中的转换规则是这样的:

  1. 如果比较的两者中有布尔值(Boolean),会把 Boolean 先转换为对应的 Number,即 0 和 1,然后进行比较。
  2. 如果比较的双方中有一方为 Number ,一方为 String 时,会把 String 通过 Number() 方法转换为数字,然后进行比较。
  3. 如果比较的双方中有一方为 Boolean ,一方为 String 时,则会将空字符串 "" 转换为 false ,除此外的一切字符串转换为 true ,然后进行比较。
  4. 如果比较的双方中有一方为 Number ,一方为 Object 时,则会调用 valueOf 方法将 Object 转换为数字,然后进行比较。

例如:

1 == { valueOf: function() {return 1;} }    // true
1 + { valueOf: function() {return 1;} }    // 2

需要强调的是,在 Javascript 中,只有 空字符串数字0falsenullundefinedNaN 这 6 个值为假之外,其他所有的值均为真值。

说到 NaN ,就不得不提一下 isNaN() 方法, isNaN() 方法自带隐式类型转换,该方法在测试其参数之前,会先调用 Number() 方法将其转换为数字。所以 isNaN('1') 这个语句中明明用一个字符串去测试,返回值仍然为 false 也就不足为怪了。

+ 号运算中还有一种更复杂的情况,那就是数字/字符串和对象进行运算的时候,上面已经举例说明了数字和对象运算的情况,我们再来说一下字符串和对象运算的情况。

当字符串和对象进行 + 运算的时候,Javascript 会通过对象的 toString() 方法将其自身转换为字符串,然后进行连接操作。

"1" + { toString: function() {return 1;} }    // "11"

之所以说它特殊,是因为当一个对象同时包含 toString()valueOf() 方法的时候,运算符 + 应该调用哪个方法并不明显(做字符串连接还是加法应该根据其参数类型,但是由于隐式类型转换的存在,类型并不显而易见。),Javascript 会盲目的选择 valueOf() 方法而不是 toString() 来解决这个问题。这就意味着如果你打算对一个对象做字符串连接的操作,但结果却是……

var obj = {
    toString: function() { return "Object CustomObj"; },
    valueOf: function() { return 1; }
};

console.log("Object: " + obj);    // "Object: 1"

隐式类型转换会给我们造成很多麻烦,那么该怎么避免呢?

建议在所有使用条件判断的时候都使用全等运算符 === 来进行条件判断。全等运算符会先进行数据类型判断,并且不会发生隐式类型转换。

您的鼓励是作者写作最大的动力

如果您认为本网站的文章质量不错,读后觉得收获很大,不妨小额赞助我一下,让我有动力继续写出高质量的文章:我的支付宝账号是 sqrtthree@foxmail.com , 点击查看二维码



个人总结:

+ 偏爱字符串String


== 偏爱数字Number


  评论这张
 
阅读(176)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017