JavaScript类型转换深度学习 - Go语言中文社区

JavaScript类型转换深度学习


JavaScript 是一门弱类型语言,刚接触的时候感觉方便快捷(不需要声明变量类型了耶!),接触久了会发现它带来的麻烦有的时候不在预期之内

呵呵一笑,哪有这么夸张,可能有人看过这样一段代码

  1. [][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])() 

这个占了好大的篇幅哈 3167 个字符,粘贴到浏览器的 Console 控制台,直接弹出了 orange,随叫随到有不有

对于不知道原理出处的给大家一个地址:http://www.jsfuck.com/

JSFuck 的变态程度达到了***,因为它的理念是 Write any JavaScript with 6 Characters: []()!+

或许又有人说:这个只是搞怪的吧,实际谁这么写代码啊

说的没错,当一段代码变得晦涩难懂的时候,甚至到上文的混乱字符(天书),却能实现任意功能这就变得不可预期,也就是说 JS 代码的安全性没有保障

当然本文不会研究这些无意义的字符原理是怎么实现的因为人家的 Github 文档已经描述的特别全面了,感兴趣的可以研究下:https://github.com/aemkei/jsfuck

我们聊一聊每天能看到用到的方法底层是怎么解析的,熟知转换分成两种一种是隐式转换,另一种是强制的类型转换

隐式转换

当遇到以下几种情况,JavaScript会自动转换数据类型:

  • 不同类型的数据进行互相运算
  • 对非布尔值类型的数据求布尔值
  • 对非数值类型的数据使用一元运算符(即 "+" 和 "-")

隐式转换为 Boolean

大多数在做 if 判断时会用到,这里只需记住六个转换为 false,其它全部为 true

  • null
  • undefined
  • NaN
  • ''
  • -0
  • +0

隐式转换为 String

字符串的自动转换,主要发生在加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。

  1. '1' + 2  // '12' 
  2. '1' + true  // "1true" 
  3. '1' + false  // "1false" 
  4. '1' + {}  // "1[object Object]" 
  5. '1' + []  // "1" 
  6. '1' + function (){}  // "1function (){}" 
  7. '1' + undefined  // "1undefined" 
  8. '1' + null  // "1null"  

隐式转换为 Number

除了加法运算符有可能把运算子转为字符串,其他运算符都会把两侧的运算子自动转成数值

  1. '5' - '2'  // 3 
  2. '5' * '2'  // 10 
  3. true - 1  // 0 
  4. false - 1  // -1 
  5. '1' - 1  // 0 
  6. '5' * []  // 0 
  7. false / '5'  // 0 
  8. 'abc' - 1  // NaN 
  9. +'abc'  // NaN 
  10. -'abc'  // NaN 
  11. +true  // 1 
  12. -false  // 0  

隐式转换的基础表现都在这了,强调的是这些转换的背后都伴随着强制转换,使用 Boolean、Number 和 String,下面重点讲一下强制转换的原理

强制转换

看到上面例子也许你已经有些许疑问了,比如上面的这个 '1' + {} 怎么就输出 1[object Object] 了呢

如上面强调的,你会猜测首先执行 String({}) 得到 "[object Object]" ,然后再字符串拼接,是的我们总能得到转换背后的实现原理,其实真实原理要比这个复杂,见下文

强制转换为 Boolean

这里略过因为与隐式转换相同,切记 []、{} 都转换成 true

强制转换为 String

基本类型的转换结果与隐式转换相同,这里说一下对象的转换,加深上面引用例子的解析

对象转换字符串分成三步

  • 先调用toString方法,如果toString方法返回的是原始类型的值,则对该值使用String方法,不再进行以下步骤
  • 如果toString方法返回的是复合类型的值,再调用valueOf方法,如果valueOf方法返回的是原始类型的值,则对该值使用String方法,不再进行以下步骤
  • 如果valueOf方法返回的是复合类型的值,则报错

再分解这个例子

  1. String({}) 
  2. // "[object Object]"  

上面代码相当于下面这样

  1. String({}.toString()) 
  2. // "[object Object]"  

如果 toString 方法和 valueOf 方法,返回的都不是原始类型的值,则 String 方法报错

  1. var obj = { 
  2.   valueOf: function () { 
  3.     console.log("valueOf"); 
  4.     return {}; 
  5.   }, 
  6.   toString: function () { 
  7.     console.log("toString"); 
  8.     return {}; 
  9.   } 
  10. }; 
  11.  
  12. String(obj) 
  13. // TypeError: Cannot convert object to primitive value  

我们不难看出可以对 toString 方法和 valueOf 方法进行改写,测试其先后运行的顺序也简单的多

  1. String({toString:function(){return 3;}}) 
  2. // "3" 
  3.  
  4. String({valueOf:function (){return 2;}}) 
  5. // "[object Object]" 
  6.  
  7. String({valueOf:function (){return 2;},toString:function(){return 3;}}) 
  8. // "3"  

结果表示toString方法先于valueOf方法执行

强制转换为 Number

基本类型转换如下

  1. Number("123") // 123 
  2.  
  3. Number("123abc") // NaN 
  4.  
  5. Number("") // 0 
  6.  
  7. Number(false) // 0 
  8.  
  9. Number(undefined) // NaN 
  10.  
  11. Number(null) // 0  

对象转换一样要复杂些,与 String 唯一不同的就是 valueOf 方法在前, toString 方法在后,其它不赘述见上文例子。

isNaN() 并不陌生,isNaN({}) //true 的内在转换过程是相同的

总结

其它的转换原则还有很多,看到这我们还是不能解释文章开始的代码转换的过程,掌握这些更多是保证正常书写代码规避错误的发生,十分好奇的可以研究下比较特殊的转化原则,还有好多好多。

版权声明:本文来源51CTO,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:http://developer.51cto.com/art/201611/520506.htm
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-16 19:34:32
  • 阅读 ( 1048 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢