译者按: JavaScript有不少坑,常常一不当心就要写bug。javascript
为了保证可读性,本文采用意译而非直译。另外,本文版权归原做者全部,翻译仅用于学习。java
JavaScript是一门伟大的语言,它拥有很是简洁的语法,庞大的生态系统,以及最重要的:有一个伟大的社区支撑着。同时,咱们也知道JavaScript是一个充满技巧性的语言。有些坑足以让咱们崩溃,也有些奇淫技巧让咱们以为颇有趣。本文的思想源自于Brian Leroux在dotJS2012上的演讲“WTFJS” at dotJS 2012。git
我收集这些例子的主要目的是将它们整理并清楚理解它们的原理。从中学到不少之前不懂的知识是一件颇有趣的事情。若是你是初学者,你能够经过学习这些笔记深刻理解JavaScript;若是你是一个专业的开发者,那么能够将这些笔记做为一个不错的引用资料。无论怎样,只要读下去,你就会学到新东西的。github
下面的函数返回的结果居然不是对象{b:10}
:小程序
(function () { return { b : 10 } })() // -> undefined
不过,若是稍微改写一下,就不同了:微信小程序
(function () { return { b : 10 } })() // -> { b: 10 }
这主要是由于有一个自动行尾加分号的机制在做怪,会自动在不少新行的行尾添加分号。在第一个例子中,其实是在return后面添加了分号。微信
(function () { return ; { b : 10 } })() // -> undefined
JavaScript坑不少,赶忙使用fundebug扶一扶!less
一个众所周知的笑话就是0.1加上0.2居然不等于0.3。ecmascript
0.1 + 0.2 // -> 0.30000000000000004 (0.1 + 0.2) === 0.3 // -> false
在StackOverflow上有关提到这样的问题“浮点数加法运算坏了(Is floating point math broken?)”:函数
你的程序中0.2和0.3会在底层用相近的数据表达。double类型数据中离0.2最近的数要比0.2大一点点。离0.3最近的double类型数据又恰好比0.3小一点点。因此,结果就是0.1+0.2的结果比0.3大。
这个问题很是出名,以致于有一个专门的网站0.30000000000000004.com。在全部使用浮点计算的语言中都有这个问题,不止JavaScript。
999999999999999 // -> 999999999999999 9999999999999999 // -> 10000000000000000 10000000000000000 // -> 10000000000000000 10000000000000000 + 1 // -> 10000000000000000 10000000000000000 + 1.1 // -> 10000000000000002
这个是依据IEEE 754-2008标准肯定的二进制浮点运算。当数值大到这个程度,它会取整到最近的偶数。参考:
你能够为Number
和String
添加自定义函数:
Number.prototype.isOne = function () { return Number(this) === 1 } 1.0.isOne() // -> true 1..isOne() // -> true 2.0.isOne() // -> false (7).isOne() // -> false
你能够想操纵其它对象同样去扩展Number对象。不过,若是定义的函数不在它自己的定义规范(Specification)中,那么不建议这么作。这里是一个参考列表:
1 < 2 < 3 // -> true 3 > 2 > 1 // -> false
咱们来看看具体的执行过程就明白了:
1 < 2 < 3 // 1 < 2 -> true true < 3 // true -> 1 1 < 3 // -> true 3 > 2 > 1 // 3 > 2 -> true true > 1 // true -> 1 1 > 1 // -> false
3 - 1 // -> 2 3 + 1 // -> 4 '3' - 1 // -> 2 '3' + 1 // -> '31' '' + '' // -> '' [] + [] // -> '' {} + [] // -> 0 [] + {} // -> '[object Object]' {} + {} // -> '[object Object][object Object]' '222' - -'111' // -> 333 [4] * [4] // -> 16 [] * [] // -> 0 [4, 4] * [4, 4] // NaN
究竟是为何呢? 下面有一个表供快速参考:
Number + Number -> addition Boolean + Number -> addition Boolean + Boolean -> addition Number + String -> concatenation String + Boolean -> concatenation String + String -> concatenation
那么其余例子呢?对于[]
和{}
,toPrimitive和toString方法会在加法操做前被隐式地调用。
// Patch a toString method RegExp.prototype.toString = function() { return this.source } /7/ - /5/ // -> 2
参考: 21.2.5.10 get RegExp.prototype.source
let f = () => 10 f() // -> 10
好的,可是下面这个呢:
let f = () => {} f() // -> undefined
你也许期待着返回{}
,而不是undefined。着主要是由于大括号也是函数定义语法的一部分。若是你真想返回大括号,能够这么写:
let f = () => ({}) f() // -> {}
Math.min(1,4,7,2) // -> 1 Math.max(1,4,7,2) // -> 7 Math.min() // -> Infinity Math.max() // -> -Infinity Math.min() > Math.max() // -> true
缘由: Why is Math.max() less than Math.min()? by Charlie Harvey
'str' // -> 'str' typeof 'str' // -> 'string' 'str' instanceof String // -> false
构造函数String
返回一个字符串:
typeof String('str') // -> 'string' String('str') // -> 'str' String('str') == 'str' // -> true
若是咱们用new来构建的话:
new String('str') == 'str' // -> true typeof new String('str') // -> 'object'
居然变成了一个对象!
new String('str') // -> [String: 'str']
参考: 21.1.1 The String Constructor
Fundebug专一于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了6亿+错误事件,获得了Google、360、金山软件等众多知名用户的承认。欢迎免费试用!
转载时请注明做者Fundebug以及本文地址:
https://blog.fundebug.com/2018/04/16/javascript-werid-series-3/