JS笔记:隐式转换

Posted Qimz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS笔记:隐式转换相关的知识,希望对你有一定的参考价值。

最近刚开始复习JS的基础知识,看到隐式转换这一块发现它的规则很多,红宝书上列出的框框又有些冗杂,所以这里我根据自己的理解总结一下其中主要的隐式转换规律。

 

1、== 操作符

  1)若存在Boolean类型 :比较相等性之前先将其转换为数值,true == 1、false == 0

  2)若存在一String类型另一数值型:比较之前先将其转换为数值,调用Number(str)

  3)若存在一Object类型另一其它:调用对象的valueOf()方法,得到基本类型后再按照前面的规则进行比较。

 

2、Number() 可将任意类型转换为数值型

  1)true==1、false == 0、“” == 0(空字符串)

  2)识别多种进制,格式正确返回数字,格式错误返回NaN

  十六进制0XA转换为十进制数字10,而后者格式无法识别返回NaN。

  3)操作数为对象时,先执行对象的valueOf(),若转换结果为NaN则调用对象的toString()方法。

  

  数组的valueOf()方法返回数组自身,toString()返回空字符串转换为数值0。

  

  对象的valueOf()方法返回对象本身,toString()返回一个对象类型名称字符串无法转换为数值返回NaN。

 

3、位运算符  非数值型Number()隐式转换后运算

  1) ~ 按位非(操作数的相反数-1)

  2) & 按位与(相同为1不同为0)

  3)  |  按位或(有一个为1就是1)

  4) ^ 按位异或(相同为0不同为1) 

  5) << 左移(不影响符号位)n<<m == n*2m

  6) >> 有符号右移(保留符号位)n>>m==n/2m

  7) >>> 无符号右移(会将负数的二进制码(补码)当作正数的二进制码运算)

 

4、逻辑运算符

  1)!逻辑非 仅返回布尔值(!! 相当于 Boolean(),将任意类型转换为布尔型)

  2) || 逻辑或:一真则真两假为假

  第一个操作数为假时返回第二个操作数;

  第一个操作数为真时返回第一个操作数。

  

  3) && 逻辑与:一假则假两真为真

  第一个操作数为假时返回第一个操作数;

  第一个操作数为真时返回第二个操作数。

  

 

  注:上述规则适用于任何操作数类型,为真(true、非空str、非零数值、任何对象),为假(false、空str、0、NaN、Null、undefined)

 

5、++/--自增自减操作符

  先对非数值操作数进行隐式Number()转换,后执行加一或减一操作。 

 

6、加减以及乘性运算符

  1)+、- 实现字符串和数值的相互转换

  字符串转换为数值:+"10" === 10 (非数值+/-操作时应用Number()转换规则)

  数值转换为字符串:10+"" === "10" (此处加号作为字符串拼接符,对数值调用toString()方法)

  2)*、/、%

  同样对非数值调用Number()后进行运算操作。

  注:% 运算符运算结果的符号取决于第一个操作数。

 

7、优先级问题(图偷来的)

  

 

8、隐式转换应用

  

  相信不少人都见过上面这一式子,乱七八糟的符号堆在一起,像我这样的初学者一看根本不知道是什么,更想不到它还能返回结果。

  接下来我就结合之前列出的一些规律简单解析一下这个式子,来看看其中的隐式转换是如何起作用并返回正确结果的。

  1)整体分析抽出骨架

  

  2)Part A  :   ( ! ( ~ + [ ] ) + { } )

  !(~ + [ ]) 加号在这里起正号作用,+[ ]经过Number()隐式转换返回0,而对0取反返回-1,最后逻辑非返回false。

  

  于是式子简化为( false + { } ),加法运算符调用Number(),上面已经说过{ }最后会调用toString()方法,进而式子变成了( false+"[object Object]" ),加法运算符碰到字符串又变成了字符串拼接符。

  

  3)Part B  :  [ --[ ~ + "" ][ +[ ] ] * [ ~ + [ ] ] + ~~! +[ ] ]

  先按将式子按隐式转换规律简化(依旧是Number())

[ --[ ~ + "" ][ +[ ] ] * [ ~ + [ ] ] + ~~! +[ ] ];

[ --[ ~ + 0 ][ 0 ] * [ -1 ] + ~~!0 ];

[ --[ -1 ][ 0 ] * [ -1 ] + ~~true ];

[ --( -1 ) * [ -1 ] + 1 ]; //两次取反返回自身

[ -2 * [ -1 ] + 1 ]; //自增减运算符优先级高于*运算符

[ 2 + 1 ]; 

  4)Part A + B = what?

  ("flase[object Object]")[3],这不就是按索引访问字符串中的值嘛,返回结果"s";

  下面也是同样套路。

  5)Part C

  两个对象最后各自调用了toString()方法,得到字符串。

  

  6)Part D  

[ [ ~! + [ ] * ~ +[ ] ] ];

[ [ ~true * -1 ] ];

[ [ -2 * -1 ] ];

[ [ 2 ] ]; 

  这里包裹的两层中括号,实际上也是应用了隐式转换,内层的数组 [2] 调用toString()最终返回数值 2;

  

  7)最后,"s"+"b"拼接起来就出现了前面的返回结果。

 

总结:

  坦白讲,像上面那样的式子除了出现在面试题中其他地方肯定是见不到的,但这也给了我们一些启示。他的隐式转换是后台自动调用的,这就增加了一些不可控性,另外自动的隐式转换还会引起额外的性能消耗。应该尽量避免隐式转换的使用让程序更稳定。

 

以上是关于JS笔记:隐式转换的主要内容,如果未能解决你的问题,请参考以下文章

简单说 通过JS的隐式转换,关键时刻救你一命

js隐式类型转换,预编译递归

scala学习笔记-隐式转换与隐式参数(18)

Scala 学习笔记之隐式参数和隐式转换并用

Js隐式转换

隐式类型转换