怪異的JavaScript系列(三)

譯者按: JavaScript有不少坑,常常一不當心就要寫bug。javascript

爲了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原做者全部,翻譯僅用於學習。java

JavaScript是一門偉大的語言,它擁有很是簡潔的語法,龐大的生態系統,以及最重要的:有一個偉大的社區支撐着。同時,咱們也知道JavaScript是一個充滿技巧性的語言。有些坑足以讓咱們崩潰,也有些奇淫技巧讓咱們以爲頗有趣。本文的思想源自於Brian Leroux在dotJS2012上的演講「WTFJS」 at dotJS 2012git

clipboard.png

我收集這些例子的主要目的是將它們整理並清楚理解它們的原理。從中學到不少之前不懂的知識是一件頗有趣的事情。若是你是初學者,你能夠經過學習這些筆記深刻理解JavaScript;若是你是一個專業的開發者,那麼能夠將這些筆記做爲一個不錯的引用資料。無論怎樣,只要讀下去,你就會學到新東西的。github

return

下面的函數返回的結果居然不是對象{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.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自定義

你能夠爲NumberString添加自定義函數:

Number.prototype.isOne = function () {
  return Number(this) === 1
}

1.0.isOne() // -> true
1..isOne()  // -> true
2.0.isOne() // -> false
(7).isOne() // -> false

你能夠想操縱其它對象同樣去擴展Number對象。不過,若是定義的函數不在它自己的定義規範(Specification)中,那麼不建議這麼作。這裏是一個參考列表:

3個number比較

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.max()比Math.min()小

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

String不是String的實例

'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

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/

相關文章
相關標籤/搜索