譯者按: 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/