對於CodeMash 2012的“Wat”演講中提到的這些奇怪的JavaScript行為,有什麼解釋?


Answers

這不僅僅是一個回答,而是因為某種原因,我不能評論你的問題。 我想更正你的JSFiddle代碼。 但是,我在Hacker News上發布了這個消息,有人建議我在這裡重新發布。

JSFiddle代碼中的問題是({}) (括號內的開放大括號)與{} (作為一行代碼的開頭處打開大括號)不一樣。 因此,當您鍵入out({} + [])您將強制{}成為鍵入{} + []時不會顯示的內容。 {} + [] 這是Javascript的整體'wat'-ness的一部分。

基本思想很簡單JavaScript想要允許這兩種形式:

if (u)
    v;

if (x) {
    y;
    z;
}

要做到這一點,有兩個解釋是用大括號表示的:1.它不是必需的 ,2.它可以出現在任何地方

這是一個錯誤的舉動。 真正的代碼沒有在中間出現的大括號,而實際的代碼在使用第一種形式而非第二種形式時往往更脆弱。 (在我上一次工作中每隔一個月大約一次,當他們對我的代碼的修改不起作用時,我會打電話給同事的辦公桌,問題是他們在“if”中添加了一行而未添加捲髮我最終採用了大括號總是需要的習慣,即使你只寫了一行。)

幸運的是,在很多情況下,eval()將復制JavaScript的全部功能。 JSFiddle代碼應為:

function out(code) {
    function format(x) {
        return typeof x === "string" ?
            JSON.stringify(x) : x;
    }   
    document.writeln('>>> ' + code);
    document.writeln(format(eval(code)));
}
document.writeln("<pre>");
out('[] + []');
out('[] + {}');
out('{} + []');
out('{} + {}');
out('Array(16).join("wat" + 1)');
out('Array(16).join("wat - 1")');
out('Array(16).join("wat" - 1) + " Batman!"');
document.writeln("</pre>");

[這也是我多年來第一次編寫document.writeln,並且對涉及document.writeln()和eval()的任何東西都感到有點骯髒。]

Question

CodeMash 2012'Wat'演講基本上指出了Ruby和JavaScript的一些奇怪的怪癖。

我在http://jsfiddle.net/fe479/9/做了一個JSFiddle的結果。

下面列出了特定於JavaScript的行為(因為我不知道Ruby)。

我在JSFiddle中發現,我的一些結果與視頻中的結果不一致,我不知道為什麼。 然而,我很想知道JavaScript在每種情況下如何處理幕後的工作。

Empty Array + Empty Array
[] + []
result:
<Empty String>

在JavaScript中使用數組時,我非常好奇+操作符。 這與視頻的結果相符。

Empty Array + Object
[] + {}
result:
[Object]

這與視頻的結果相符。 這裡發生了什麼? 為什麼這是一個對象。 +運營商做了什麼?

Object + Empty Array
{} + []
result
[Object]

這與視頻不符。 視頻顯示結果為0,而我得到[Object]。

Object + Object
{} + {}
result:
[Object][Object]

這與視頻不匹配,以及如何將變量結果輸出到兩個對象? 也許我的JSFiddle是錯誤的。

Array(16).join("wat" - 1)
result:
NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN

做wat + 1結果在wat1wat1wat1wat1 ...

我懷疑這只是簡單的行為,試圖從字符串中減去一個數字導致NaN。




我們可能會參考該規範,這很好,也是最準確的,但大多數情況下也可以通過以下語句以更易理解的方式進行解釋:

  • +-運算符只能使用原始值。 更具體地說, + (加法)可以與字符串或數字一起使用,而+ (一元)和- (減法和一元)僅適用於數字。
  • 所有原始函數或操作符都將原始值作為參數,將首先將該參數轉換為所需的基元類型。 它是通過valueOftoString ,它可以在任何對像上使用。 這就是為什麼這些函數或操作符在對對象調用時不會拋出錯誤的原因。

所以我們可以這樣說:

  • [] + []String([]) + String([])相同,與'' + '' 。 我在上面提到過, + (加法)對於數字也是有效的,但是在JavaScript中沒有有效的數組表示形式,所以使用了字符串的添加。
  • [] + {}String([]) + String({})相同,與'' + '[object Object]'
  • {} + [] 。 這一點值得更多解釋(參見Ventero答案)。 在這種情況下,花括號不是作為對象處理,而是作為空白塊處理,因此它與+[]相同。 一元+僅適用於數字,因此實現嘗試從[]獲取數字。 首先它嘗試valueOf ,在數組的情況下返回相同的對象,然後它嘗試最後的手段:將toString結果轉換為數字。 我們可以將它寫為+Number(String([])) ,它與+Number('')相同,與+0相同。
  • Array(16).join("wat" - 1)減法-僅適用於數字,因此它與Array(16).join(Number("wat") - 1) ,因為"wat"不能被轉換為有效的號碼。 我們接收NaN ,並且NaN任何算術運算都以NaN結果,所以我們有: Array(16).join(NaN)