Javascript中的类型转换

Javascript为何会有类型转换

Javascirpt世界里,不推荐大量的使用try...catch...,我想大概缘由:前端

  • JS里任何类型之间的算数运算,逻辑运算和位运算都不会抛异常或者错误。例如 1/0 == Infinity, 0/0 = NaN, [ ] + 1 = '1' 等。因此catch到excepton/error的概率,相对于编译型语言甚至于python/ruby等动态语言,是大大地下降了。python

  • try...catch...会在catch里转换到一个新的做用域,catch里面调用本函数或者函数外的对象时,增长了一层做用域的查找,下降了运行效率web

  • 若是有未知的风险,确实能够try...catch...。可是若是你的代码里有比较多的try...catch...,这就是bad smell,说明须要增强coding质量或者重构了。typescript

类型转换法则

这里讨论JS里对不一样类型进行运算的时候,是如何作类型转换的(通常是隐式转换)。编程

加法运算

  1. 1 + '-1' = '1-1'
    基本类型之间相加时,只要其一是字符串,另一个也会先转换为字符串,结果就变成字符串的链接。后端

  2. [ ] + 1 = '1'
    引用类型和基本类型相加。引用类型先转化为基本类型。转化过程:先查看对象的valueOf()方法是否返回基本类型。数组的valueOf返回它自己,属于object类型,不是基本类型。因此再调用toString方法。空数组[]的toString返回空字符串。结果转为‘’ + 1. 返回字符串‘1’。数组

  3. [ ] + { } = [object Object]
    引用类型之间的加法。引用类型需先转换为基本类型。 参考2,空数组[]转为空字符串。相似地空对象{ } 转换时,也先查看{ }.valueOf(). 由于 {}的valueof方法返回它自身,因此会调用{}.toString()返回‘[object Object]'。
    这样结果变成 '' + '[object Object]' = '[object Object]'ruby

  4. 1 + null = 1
    由于已是基本类型,并且没有字符串,因此会基于number类型运算。 null转为0, 结果是 1 + 0 = 1函数

  5. 1 + undefined = NaN
    undefined 转为NaN, so 1+ NaN = NaN学习

  6. false + null = 0
    都是基本类型并且没有字符串,因此基于数字类型相加。 false转为0, null也为0. 结果 0 + 0 = 0

  7. [1] + [2] = '12'
    分别调用toString方法以转为基本类型,获得'1'和‘2’, '1' + '2' = '12'

加法之外的算数运算

加法之外的算数运算,若是有object类型(包括数组),先转为基本类型,这和加法运算是相同的。转换过程也是先查看valueOf是否返回基本类型,若是不是,就调用toString(这里假定toString都返回string。除非谁闲着没事,非得给一对象的toString返回对象类型?)

和加法运算不一样的是,转换为基本类型后,全部的基本类型再转为number类型,最终以number类型进行运算。

  1. 1 - "-1" = "-1"
    字符串“-1”转为number的-1, 结果1 - (-) = 2

  2. [ ] - 1 = -1
    [ ]先转为基本类型,是空字符。空字符再转为number为0 ,结果是0 - 1 = -1

  3. [ ] / { }
    空数组转为基本类型是空字符,空对象转为基本类型是[object Object],两者再分别转为数字类型是 0 和 NaN,最终结果为0/NaN = NaN

  4. 1 / null
    都已经为基本类型,因此只要把null转为number类型的0, 而后1 / 0 = Infinity

  5. 1 * undefined
    都已经为基本类型,因此只要把undefined转为number类型的NaN, 而后1 * NaN = NaN

逻辑运算

  1. 1 && null = null.
    由于1 是真值,则返回第二个值, 即null

  2. null && undefined = null
    返回null,由于null是falsy,则返回第一个。

  3. 0 || {} = {}
    返回 {}. 由于0 是falsy,返回第二个

  4. 1 || null = 1
    返回1, 由于1是真值,返回第一个

位运算

  1. ~n = -(n+1)
    例如~25 = -26. 这里是带符号的取反。若是是无符号的取反,结果就不同了,有兴趣的能够在C语言里试试 ~25u

  2. ~null = -1
    null转为0, ~0 = -(0+1) =-1

  3. ~undefined //SyntaxError: Invalid or unexpected token

  4. ~~23.5 = 23 ~~-23.5 = -23
    但 Math.floor(-23.5) = -24. 故而通常用~~取整数位

If 运算

if(-1)if (-1 == true) 是不同的。前者是真假判断: -1是truthy,是真值。后者相似算术运算:先转为number,true 转为1, 故而 -1 == 1是假值。

小结

这里总结了js类型转换和运行的基本规律,但愿是能够知足基本的项目须要了。

后记

JS不一样类型之间的类型转换,确实是让人挠头的语言。我猜测多是JS产生的时候,web方兴未艾,web工程师的编程功底尚未很规范(至少没有今天这么多资料书籍和培训机构等),因此js容许类型转换,不一样类型之间运算时,保证不抛异常或者尽可能少抛。

可是如今前端和后端同样的庞大了,显然js的这样那样的技法每每会使工程师掉入陷阱。typescript应允而生,一个目的是也是帮助初级工程师写出还能够的代码(另一个目的估计是下降后端开发者写前端的门槛和思惟转变)。从这角度解读,ts也是为知足项目工程和公司的须要。若是想深刻js学习,原生的js(es5/6)是绕不开的。

补证

前面提到“try...catch...会在catch里转换到一个新的做用域”,这是在《你不知道的JavaScript》中卷里看到的。后来感受仍是作些论证,不然老以为不踏实。看以下代码:

function testException() {
    var error = 'outer error'
    try {
        throw 'inner error'
    } catch (error) {
        console.log(error)
        error = 'modify inner error'
    }
    
    // 这里会输出 outer error(而不是modify inner error),
    // 说明catch...里修改的error,不是testExecution()函数做用域里的,而是一个“新”做用域里的error
    // 因此咱们可认为,catch...建立了一个新的做用域。看来它和函数做用域的相似点,都接受“参数”
    console.log(error) 
}

testException()
相关文章
相关标签/搜索