怪異的JavaScript系列(一)

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

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

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

<div style="text-align: center;">
<img style="width:80%;" src="javascript-werid-series-1/brian.jpeg" />
</div>java

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

[]等於![]

[ ] == ![ ] // -> true

相等(==)判斷操做會將兩邊的類型都轉換爲數字(number),而後再比較。由於[]![]都會轉換爲0。咱們能夠理解[]是一個數組,只不過爲空而已,那麼爲true。右側![]則爲false。false而後轉換爲數字0。左側[]直接轉換爲數字,由於空數組會轉換爲0,因此儘管咱們認爲[]爲true,這裏卻變成了0github

下面是簡化的計算過程:算法

+[] == +![]
0 == +false
0 == 0
true

參考:數組

true 是 false

!!'false' ==  !!'true'  // -> true
!!'false' === !!'true' // -> true

true是一個真值,用1表示;字符串的「true」則爲NaN。瀏覽器

true == 'true'    // -> false
false == 'false'  // -> false

'false'是一個有意義的字符串。less

!!'false' // -> true
!!'true'  // -> true

參考:7.2.13 Abstract Equality Comparison

baNaNa

'b' + 'a' + + 'a' + 'a' // -> baNaNa

這是一箇舊笑話,不過改進過的。原始的長這樣:

'foo' + + 'bar' // -> 'fooNaN'

該表達式以'foo' + (+'bar')的形式計算,由於bar不是數字,因此轉換爲NaN。

參考:

NaN不等於NaN

NaN === NaN // -> false

根據===的算法,咱們能夠容易理解爲何爲false。

若是typeof(x)和typeof(y)不一樣,那麼返回false.
不然,若是typeof(x)是Number,那麼

  1. 若是x是NaN,那麼返回false;
  2. 若是y是NaN,那麼返回false;
  3. ...

由此能夠得出值爲false的結論。

fail

(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]] // -> fail

若是咱們仔細觀察序列的規律,會發現下面的模式出現不少次:

(![]+[]) // -> 'false'
![]      // -> false

所以,咱們嘗試將[]和false相加。可是根據內部一些列函數的計算(binary + Operator -> ToPrimitive -> [[DefaultValue]]),右側的[]最終轉換爲string:

(![]+[].toString()) // 'false'

對於一個字符串,咱們就能夠經過下標來獲取對應的字符:

'false'[0] // -> 'f'

剩下的都很直觀,除了i很取巧。fail中的i是經過在falseundefined中獲取第十個下標對應的字符而獲得。

[]包含值,但不是true

空數組不等於true。(An array is a truthy value, however, it's not equal to true.)

!![]       // -> true
[] == true // -> false

參考:

null不等於false

儘管null是一個false的值,可是null不等於false。

!!null        // -> false
null == false // -> false

不過,若是和其它false的值比較,那麼他們又是相等的。

0 == false  // -> true
'' == false // -> true

參考: 7.2.13 Abstract Equality Comparison

JavaScript坑不少,趕忙使用fundebug扶一扶!

document.all是一個對象,不過是undefined

⚠️這個是前端瀏覽器API,在Nodejs環境沒法使用。

儘管document.all能夠返回一個像數組同樣的對象,能夠用來訪問DOM節點。可是呢,經過typeof查看document.all,你會驚訝地發現類型是undefined

document.all instanceof Object // -> true
typeof document.all // -> 'undefined'

並且,document.all並不等於undefined。

document.all === undefined // -> false
document.all === null // -> false

並且,更驚訝的是:

document.all == null // -> true

document.all是一個過去經常使用的獲取DOM元素的方法,特別是老版本的IE。可是從未進入標準,儘管普遍使用在過去的JS代碼中。當新的API突出來(好比document.getElementById)後,document.all就被淘汰了。標準委員會不得不以爲怎麼處理它。但是由於它已經被普遍使用,因此委員會以爲保留它,可是違背了JavaScript的規範。

參考:

最小值比0還大

Number.MIN_VALUE是最小的數,可是它比0還大。

Number.MIN_VALUE > 0 // -> true

由於Number.MIN_VALUE5e-324。也就是說即便最小的值也能夠用浮點數表示出來,雖然離0很接近,可是依然比0大。其實最小的數是Number.NEGATIVE_INFINITY,儘管它不是一個實際存在的數。

在StackOverflow有相關問題:Why is 0 less than Number.MIN_VALUE in JavaScript?

參考: 20.1.2.9 Number.MIN_VALUE

相關文章
相關標籤/搜索