2013-06-01 52 views
7

這個Javascript表達式在所有的瀏覽器(jsfiddle)工作得很好:表達與條件,並賦值運算符

false ? 1 : x = 2; 

它評估爲2

但是,爲什麼?我希望這裏有個例外,因爲作業的左側是false ? 1 : x,這不是有效的參考。與(jsfiddle)比較:

(false ? 1 : x) = 2; 

這一個是拋出一個ReferenceError。我仔細檢查了Javascript operator precedence table,它聲明條件運算符? :比賦值運算符=具有更高的優先級,所以兩個表達式應該是相同的,至少我儘管如此。

在Java中,它具有與JavaScript類似的語法和運算符優先規則,上述兩個表達式都會導致編譯時錯誤,這非常合理。

有人可以解釋這種差異嗎?

+3

通知,即[條件運算](HTTP://es5.github .io /#x11.12)會返回值,而不是引用。 – Teemu

+2

@Teemu - 其中_value_實際上可能是一個參考。例如'(false?func1:func2)();' – nnnnnn

+0

@nnnnnn你說得對,雖然OP在這個例子中只有一個變量。其實你已經在你的回答中提到了這一點,只是對我的閱讀不好...... – Teemu

回答

9

這裏有兩個關鍵瞭解JavaScript條件表達式和Java條件表達式的區別:

請在ECMAScript的5註釋規範的這個部分的底部閱讀現在

http://es5.github.io/#x11.12

,請閱讀條件表達式Java規範部分:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25

你會注意到,作爲ECMAScript的5注狀態,在三元運算符第三個操作數在Java中不能只是任何舊的表達 - 它只能是一個條件表達式。但是,對於ECMAScript 5,第三個操作數可以是任何AssignmentExpression。

在Java規範進一步看,我們看到的是表達任何賦值表達式:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.27

但條件表達式或者是與三元操作符(......的條件表達式:?.. 。)或者只是一個ConditionalOrExpression(在ES5中稱爲LogicalOrExpression)(參見上面關於該信息的前兩個鏈接中的任何一個)。在什麼樣的ConditionalOrExpression可以在這裏是開始於Java的 「產業鏈」:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24

在ECMAScript中5

在這裏:

http://es5.github.io/#x11.11

繼在表達類型的 「鏈」 落後ECMAScript 5規範(因爲它比Java規範更容易遵循)從條件表達式一直到基本上所有其他表達式,但分配表達式最終讓我們在開始 - 主表達式:

http://es5.github.io/#x11.1

兩個以上的代碼段的第二個操作數是主表達式:

1 

這一切rigamarole(如果我是正確的)的結果是,在Java中,第三個操作數三元運算符不能是一項任務,但可以在JavaScript中使用。這就是爲什麼你的兩個例子在Java中失敗,而在JavaScript中卻只有第二個。

爲什麼第一個使用JavaScript而不是第二個?

operand1 ? operand2 : operand3; 

像工作以下IIFE代碼(不實際上,但下面的代碼是說明如何將上述工程):

(function() { if (operand0) return operand1; else return operand2;}()); 

所以:

false ? 1 : x = 2; 

變成(再次,不是實際上 - 下面的代碼是說明性的上面的代碼):

(function() { if (false) return 1; else return x = 2;}()); 

然而,在第二個片斷,使用的括號的情況下,從分離出明確的條件表達式「= 2;」 :

(false ? 1 : x) = 2; 

變成(再次,不實際上 - 下面的代碼是說明性的上面的代碼):

(function() { if (false) return 1; else return x;}()) = 2; 

三元運算符的「行爲像例子IIFE函數調用」行爲將返回任何x是,並且這將是一個,而不是無法指定的引用。因此錯誤。這將像下面的代碼(如果x === 3):

3 = 2; 

顯然,一個不能這樣做。在Java中,我相信,第一個錯誤是因爲第三個操作符不能被賦值,第二個賦值錯誤,因爲你不能賦值(就像在JavaScript中一樣)。

至於運算符優先級,請看下面的代碼:

var x = 3; 

console.log(false ? 1 : x);   // ?: evaluates to "3" 
console.log(false ? 1 : x = 2);  // ?: evaluates to "2" 
console.log(false ? 1 : x = 2, 4); // ?: evaluates to "2" - "2" and "4" arguments passed to log 
console.log((false ? 1 : x = 2, 4)); // ?: evaluates to "4" 

在上面的IIFE說明性代碼方面觀察時,前兩個是容易理解。

在第一行中x被評估,條件表達式評估爲3 - 這很容易。

在第二行中,我可以描述它的最佳方式是條件運算符(?:)甚至會導致將較低優先級的'='運算符評估爲完整表達式,這不是因爲(?:)具有較高的優先級,但是因爲規範說明':'後面的賦值表達式作爲AssignmentExpression被評估(包括'= 2'部分)。這種行爲在上面IIFE示例的return語句中看起來更清晰。至少使用JavaScript,不僅可以在第二個操作數中進行賦值,還可以在條件表達式的第三個賦值中進行賦值。

但是,在第三行中,在「x = 2」表達式中已經找到完整的賦值表達式,並且三元運算符將其用作完整的第三操作數,並且','運算符的優先級低於任何另一方面,我們得到等效於以下代碼:

console.log((false ? 1 : x = 2), 4); 

在代碼的第四行,在括號中的console.log()語句內包封整個表達式帶來「 4' 到」?: '三元表達式作爲第三操作數的一部分。

下面的jsfiddles演示了上述與實時代碼的討論。請注意,前兩個具有相同的確切的錯誤打印 '2' 兩次後:

FIDDLE1

FIDDLE2

FIDDLE3

+2

有人可能會爭辯說,這些函數實際上像表達式一樣,在語義上有所不同,但這不是重點。這裏只涉及很多重要的含義。因此,我花了一段時間來查看Java和Javascript的語法規則,以瞭解如何分析表達式。我意識到這並不像運算符優先級表所示那麼簡單。這是有道理的,我說得不太對,說這個語法是相似的。這是一個很好的答案。 –

+0

注意到語義差異。好點子。也許術語「幫助理解」或「類似於」會更好?我無法想出一個更好的方法來幫助演示實時代碼中發生的事情,因此IIFE似乎對移動討論以及至少在jsFiddle中演示至少是類似的東西很有價值。 – Aeoril

+0

@ GOTO0 - 我更新了我的答案,以便在提及我的IIFE類似物時擺脫「語義上的」一詞,而是使用術語「說明性的」 – Aeoril

14

當你發現在MDN,? :比賦值運算符=,這意味着JS是讀你的語句作爲優先級數字:

false ? 1 : (x = 2); 

乍一看這似乎倒退,但它意味着什麼是? :期待三個操作數,其中:右側的部分是第三個操作數。由於=的優先級較低,因此x = 2成爲第三個操作數。

警報顯示2因爲賦值x = 2設置x變量2然後將此(子)的表達計算爲2

你的第二個版本:

(false ? 1 : x) = 2; 

...給出了一個參考錯誤,因爲它的(false ? 1 : x)部分首先它評估與xundefined)相關的值,它不返回變量x本身。 undefined = 2不起作用。

+1

對不起,我不明白你的答案的第一句話。我認爲優先級更高的運營商會先評估,而不是最後評估。這裏爲什麼不同? –

+1

'?:'部分首先被處理,爲了完全評估它,它必須有三個操作數,所以解釋器必須弄清楚操作數是什麼,在這種情況下,第三個操作數是表達式'x = 2'。這就是我在上面第二段中試圖說的。請注意,如果你說'真的? 1:x = 2「x = 2」部分根本沒有得到評估,「x」保留了其以前的值。 – nnnnnn

0

我也不會轉回去碼這種方式,但it's工作的事實是明顯的對我說:與你的聲明?:

啓動的優先級高於= - thats's錯誤的,因爲?:有15個,而=有17
因此第一代碼類似於 false ? 1 : (x = 2); - 從那裏它很清楚什麼在我看來發生的事情,這就是類似於 if (false) 1; else x=2;

你的第二個合作de片段不能工作,因爲=的左側是undefined,你不能分配任何東西給undefined,就像ReferenceError表示的那樣。(?)

+1

'?:'的優先級高於'='。根據OP鏈接到表格頂部的解釋,15的優先級高於17。 – nnnnnn

5

三元操作者需要三個值:一個條件,一個如果真如果假

在表達式

false ? 1 : x = 2 

編譯器看到作爲條件,作爲如果真和X = 2。既然?優先於= x = 2尚未評估。所以,由於虛假本質上是錯誤的,返回的是x = 2

當評價x = 2時返回2.

因此,爲什麼可以寫

x = y = 2 

在該示例中,x和y都被設置爲2。

的整個原因x = 2被視爲if-false操作數而不僅僅是x是因爲三元運算符將所有內容都放在:if if-false如果它在範圍內。

當您使用方括號但是您要做的是將文字(無論x是)設置爲2,導致錯誤。

我無法回答爲什麼在JavaScript中它的工作原理,但它導致java中的錯誤。我只能假設稍微不同的運營商優先級?