js很奇怪的問題,關於加法運算的問題?

console.log(1+ +"2");//3 類型是number

console.log(1+" "); //1 類型是string

console.log(1+ +""); //1 類型是number

這是為什麼呢


只是規範規定

一個個說

1+ +"2"

注意這裡有個空格,不會成為 ++ 運算符,因為與++的parse要求不符,會分開。

所以在parse 中是類似是

[1, 運算符+,表達式[一元運算符+, 字元串2]]

先進行表達式求值

表達式內是個一元運算符+

它的求值是 ES http://www.ecma-international.org/ecma-262/5.1/#sec-11.4.6

其中 expr 是字元串2,執行到 2 步驟會被 ToNumber,轉為數值2後,結構變為

[1, 運算符+,2]

此時是 ES的+運算 ECMAScript Language Specification

根據 + 運算說明

執行到 8步驟 lprim (左值) rprim(右值)均 ToNumber 後相加,結果為3.

1+" "

parse

[1, 運算符+,空字元串]

同根據 ES的+運算 ECMAScript Language Specification

執行到 7 判斷出 rprim 是 String,則lprim 和 rprim 均 ToString 後連接。

結果為字元串 「1」.

1+ +""

parse 同 第一個

[1, 運算符+,表達式[一元運算符+, 空字元串]]

先進行表達式求值

表達式內是個一元運算符+

它的求值是 ES http://www.ecma-international.org/ecma-262/5.1/#sec-11.4.6

其中 expr 是空字元串,執行到 2 步驟會被 ToNumber,轉為數值0後(見注1),結構變為

[1, 運算符+,0]

執行到 8步驟 lprim (左值) rprim(右值)均 ToNumber 後相加,結果為1.

【注1】:

其中 ToNumber 對 string 的處理需要看ECMAScript Language Specification

其中有說

A StringNumericLiteral that is empty or contains only white space is converted to +0.

空字元串和只包含空格的轉為 +0 (ES 的0 是帶符號的有+0 和-0)


js的隱式轉換,高程里說了蠻多的。

+運算符在兩邊都是Number類型的時候,會直接運行我們所熟悉的數學加法運算。-運算符亦然。

對於 +運算符 ,兩邊有其一為字元串(String類型),有以下好幾種情況:

  1. 另一邊為String類型的時候,直接連接兩字元串,這不用多說了吧,其實和String類型的concat方法有一樣的效果的。
  2. 另一邊為Number,Boolean類型的時候,會調用其自身的toString()方法對其進行轉換成相應地字元串,至於這些基本類型為什麼可以使用toString()方法,這又是js底層的一種內部轉換的實現了,不多說,與題無關。

  3. 另一邊為NULL,undefined類型的時候,由於這些類型無toString方法,內部轉換的時候會使用String()對其進行轉換。
  4. 另一邊為Object、Function類型時,首先你要知道他們有valueOf和toString這兩種轉換的方法,每個Object和Function類型默認都有toString,而valueOf方法需自己定義,當該對象有valueOf得時候,內部類型轉換的時候會調用valueOf進行轉換,沒有的話會調用toString進行轉換,這就不用舉例子了吧,馬上打開控制台試一下又不是什麼難事。

說完 +運算符,說一下-運算符吧

String類型不能單純使用-運算符進行相減,減法只存在於數學運算,這沒問題吧。

所以,當使用-運算符的時候,對於非Number類型都會轉換成Number然後再進行數學運算,對於Boolean,String,Null,nudefined類型會調用Number()對其進行轉換,而對於Object,如上面第4點所說對其先轉換成String類型然後再使用Number()轉換成Number類型。

(js真麻煩。。。。

而為什麼1+ +"2"的結果是3呢,在運算時,js先執行 +"2" ,這相當於Number("2"),這也沒什麼好糾結的把,就當做js的語法糖就是了,"+變數" 的處理和-運算符的處理差不多,打開控制台試試吧。

對了,關於@Danilo說提到的 +new Date(),他實際上返回的是從1970.1.1至今的毫秒數,和Date.now()的做法一樣,不過某些低版本瀏覽器不支持Date.now()這個方法,不過可以用+new Date()替代之。


以後別寫這種偏門寫法

習慣這麼寫的人最好早點開除


別問我為什麼,隱式類型轉換,天知道 JavaScript 什麼時候會不高興,不同引擎反應可能還不一樣。有興趣可以研究下規律,但是最好的解決方案是——不要這樣寫代碼。

====================

看到有人說理解的基礎之上想用就用...我只能說...呵呵...

可以測試以下代碼的輸出:

var a = 1;
console.log("2" + a - a);
console.log("2" - a + a);

看看理解了隱式類型轉換後 JavaScript 是不是就真能 make you happy 了...這還只是冰山一角。

====================

再補充一下,問題中的代碼的確沒有出現異常,1+ +"2" === 1+(+"2"),第三個同理,而三者都發生了隱式類型轉換,"2" =&> 2,"" =&> 0。注意兩個 + 號中間要有空格,不然會被當作 ++ 運算符處理,而 ++ 運算符的 left-hand 必須是合法的 expression,1 並不合法,因此會報錯。

而且,好在現在主流的代碼壓縮工具會把 1+ +"2" 轉為 1+2,不然簡單粗暴的幹掉空格,鬼知道會發生什麼。

最後我堅持觀點,不要這樣寫代碼!坑死爹不償命!


首先我是手機不請自答! 因為藏不住心中的怒火!

這是100px的大字

【不要寫這種代碼,就算真的必須這麼做,請帶上()! 最後別去寫這種!】

解答

+"" 其實就是 數字0 不要問為什麼!記住就行!js隱式轉換,能讓你哭死!


這種東西不要玩,害死人,學也不要學。

想了解為什麼,看犀牛書的隱式轉換。

我猜測,是1++""後面的加號視為+-正負,優先順序高,所以先轉換為0再和前面加,自然是數字。


規則是下面這樣的,另外加上 (+"") = Number("") 這樣的強制轉換成number就能得到結果了。

至於為什麼會這樣你應該深入了解組織。


很簡單啊,String/Date/Object,前面放個加號,會產生類型轉換,轉成 Number 類型

記得以前和某同學一起討論過,印象中還是根正苗紅的 ECMAScript 規範產物,有興趣可以查一下 ECMA 文檔,有詳細說明

補充:

查了一下 Standard ECMA-262 5.1 Edition / June 2011 ,記憶還是沒偏差的。(順嘴打上了w3c,我不嚴謹了,騷瑞)

ECMAScript 說得很明白了,加號後面跟一個操作元,叫 Unary + Operator ,會將操作元轉換為 Number 形式。

而隱式類型轉換,則是在加法運算中,左式或右式出現字元串類型時,將其餘表達式轉換為字元串(調用 toString() )

一元操作符原文:

11.4.6Unary + Operator

The unary + operator converts its operand to Number type.

The production UnaryExpression : + UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.
  2. Return ToNumber(GetValue(expr)).

加法運算原文:

11.6.1The Addition operator ( + )

The addition operator either performs string concatenation or numeric addition.

The production AdditiveExpression : AdditiveExpression + MultiplicativeExpression is evaluated as follows:

  1. Let lref be the result of evaluating AdditiveExpression.
  2. Let lval be GetValue(lref).
  3. Let rref be the result of evaluating MultiplicativeExpression.
  4. Let rval be GetValue(rref).
  5. Let lprim be ToPrimitive(lval).
  6. Let rprim be ToPrimitive(rval).
  7. If Type(lprim) is String or Type(rprim) is String, then
    1. Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)
  8. Return the result of applying the addition operation to ToNumber(lprim) and ToNumber(rprim). See the Note below 11.6.3.

NOTE 1No hint is provided in the calls to ToPrimitive in steps 5 and 6. All native ECMAScript objects except Date objects handle the absence of a hint as if the hint Number were given; Date objects handle the absence of a hint as if the hint String were given. Host objects may handle the absence of a hint in some other manner.

NOTE 2Step 7 differs from step 3 of the comparison algorithm for the relational operators (11.8.5), by using the logical-or operation instead of the logical-and operation.

至於題主的寫法,其實是這樣的:

1 + +"2" =&> 1 + (+"2")

這就清晰了

這種寫法通過上面截圖能看到,對於 Date 類型,可以很方便取時間戳,兼容性很好噢

而且遇到伺服器返回的時候,可以這麼寫:

$.get("url").then(function (d) {
if (d +d.status === 1) {
// do somethings.
} else {
// do other things.
}
});

好處嘛,很明顯,當 d 為空,或者 status 屬性不存在時候,不會報錯阻斷 JS 執行,而是順利的走到 else:

想起某差點被爆頭的總統說過:不是語法坑人,是人坑人。想用就用吧,理解的基礎上用就好。


你是不是連看書都懶得了?


+會觸發類型轉換。

typeof +"" === "number"


1、 +『2』轉成數字2,所以1+ +『2』等於3

2、 1+『 』(空格)字元串 1轉字元串 所以等於"1

3、 1+ +""(空字元串轉成數字0) 所以等於1


+是一目運算符,在js裡面可用於強制類型轉換,string to number。另外加法在運算的時候如果有字元串,會優先進行字元串連接。

這些嘛屬於前端冷知識的範疇!很多人喜歡用,也有很多人不喜歡用,不過在我看來,如果能少寫兩行代碼為什麼不少寫呢! 很多人說不利於代碼閱讀,其實,作為一個敲代碼的,看到不理解的應該第一時間去console裡面試試,然後再去查查資料什麼的~

放心用吧。ps:還有「12」 | 0 也會返回數字


推薦閱讀:

如何評價前端應用框架 dva?
如何在 JS 中嵌入 HTML 代碼?
js浮點數精度問題的前世今生?
為什麼JS中一個浮點數位或0會去掉小數部分?
怎樣精確區分這些名詞:庫、插件、組件、控制項、擴展?

TAG:前端開發 | JavaScript | JavaScript語言精粹 |