JS加法運算全解析
終極命題:
在JS中:[]+[]、[]+{}、{}+[]、{}+{}的結果分別是什麼?
一、JS中的型別
-
基本型別
JS的基本型別包括Undefined、Null、Boolean、Number和String五種。Undefined型別和Null型別的都只有一個值,即undefined和null;Boolean型別有兩個值:true和false;Number型別的值有很多很多;String型別的值理論上有無數個。 -
值型別
JS中的值有原始型別(Primitive)和物件型別(Object)。在做相加等操作時,不是原始型別的要先轉換為原始型別,再執行相關的操作。
二、JS中的加法運算
1、使用ToPrimitive運算轉換左右運算元為原始資料型別(primitive)。
2、在轉換後,如果其中一個運算元出現原始資料型別是“字串”型別值時,則另一運算元強制轉換為字串,然後做字串的連線運算。
3、在其他情況時,所有運算元都會轉換為原始資料型別的“數字”型別值,然後作數字的相加。
三、ToPrimitive內部運算
加號運算子只能用於原始資料型別,對於物件型別的值,需要進行資料轉換。在ECMAScript中,有一個抽象的ToPrimitive運算,用於將物件轉換為原始資料型別,在物件的加法、關係比較或值相等比較的運算中,都會用到。
關於ToPrimitive的說明語法:
ToPrimitive(input, PreferredType?)
input代表代入的值,PreferredType可以是數字(Number)或字串(String)其中一種,表示需要優先轉換的原始型別。但如果沒有提供這個值也就是預設情況,則會設定轉換的hint值為"default"。這個首選的轉換原始型別的指示(hint值),是在作內部轉換時由JS視情況自動加上的,一般情況就是預設值。
而在JS的Object原型的設計中,有兩個方法,valueOf與toString,在物件的資料型別轉換過程中會根據傳入的值調整被呼叫的順序。
PreferredType為數字(Number)時
當PreferredType為數字(Number)時,input為要被轉換的值,轉換input值的步驟:
1.如果input為原始資料型別,直接返回input。
2.否則,input是物件,呼叫valueOf()方法,如果能得到原始資料型別的值,返回這個值。
3.否則,input是物件,呼叫toString()方法,如果能得到原始資料型別的值,返回這個值。
4.否則,丟擲TypeError錯誤。PreferredType為字串(String)時
1.如果input是原始資料型別,直接返回input。
2.否則,input是物件,呼叫toString()方法,如果能得到原始資料型別的值,返回這個值。
3.否則,input是物件,呼叫valueOf()方法,如果能得到原始資料型別的值,返回這個值。
4.否則,丟擲TypeError錯誤。PreferredType未提供(default)時
PreferredType預設型別為Number,所以先呼叫valueOf(),再呼叫toString()。
其中比較特殊的是Date物件和Symbol物件,他們覆蓋了原來的PreferredType行為,Date物件預設首選型別是String。
四、valueOf()和toString()
valueOf()和toString()是Object上的兩個方法,但是在JS中,可能會根據Object之間的差異,返回值有所不同。
-
普通的Object物件
valueOf():返回物件本身。
toString():"[object Object]"字串值,不同的內建物件的返回值是"[object type]"字串,"type"指的是物件本身的型別識別,例如Math物件是返回"[object Math]"字串。但有些內建物件因為覆蓋了這個方法,所以直接呼叫時不是這種值。(注意: 這個返回字串的前面的"object"開頭英文是小寫,後面開頭英文是大寫)。
利用Object中的toString來進行各種不同物件的判斷語法:
Object.prototype.toString.call([])
"[object Array]"
Object.prototype.toString.call(new Date)
"[object Date]"
需要配合call,才能得到正確的物件型別值。
Array(陣列)
Array(陣列)雖然是個物件型別,但它與Object的設計不同,它的toString有覆蓋,說明一下陣列的valueOf與toString的兩個方法的返回值:
valueOf(): 返回物件本身
toString(): 相當於用陣列值呼叫join(',')所返回的字串。也就是[1,2,3].toString()會是"1,2,3",這點要特別注意。Function物件
Function物件很少會用到,它的toString也有被覆蓋,所以並不是Object中的那個toString,Function物件的valueOf與toString的兩個方法的返回值:
valueOf(): 返回物件本身
toString(): 返回函式中包含的程式碼轉為字串值。Date物件
valueOf(): 返回給定的時間轉為UNIX時間(自1 January 1970 00:00:00 UTC起算),但是以微秒計算的數字值
toString(): 返回本地化的時間字串
五、Number、String、Boolean包裝物件
JS的包裝物件是必須使用new關鍵字進行物件例項化的,直接使用Number()、String()與Boolean()三個強制轉換函式的用法。例如new Number(123),而Number('123')則是強制轉換其他型別為數字型別的函式。
包裝物件
包裝物件是JS為原始資料型別數字、字串、布林專門設計的物件,包裝物件的valueOf與toString的兩個方法在原型上有經過覆蓋,所以它們的返回值與一般的 Object的設計不同:
valueOf方法返回值: 對應的原始資料型別值
toString方法返回值: 對應的原始資料型別值,轉換為字串型別時的字串值
toString方法會比較特別,這三個包裝物件裡的toString的細部說明如下:
1、Number包裝物件的toString方法: 可以有一個傳參,可以決定轉換為字串時的進位(2/8/16)
2、 String包裝物件的toString方法: 與String包裝物件中的valueOf相同返回結果
3、Boolean包裝物件的toString方法: 返回"true"或"false"字串-
強制轉換
Number()、String()與Boolean()三個強制轉換函式,所對應的就是在ECMAScript標準中的ToNumber、ToString、ToBoolean三個內部運算轉換的對照表。通過ToNumber()把值轉換成Number:
引數 結果 undefined NaN null +0 boolean true被轉換為1,false轉換為+0 number 無需轉換 string 由字串解析為數字。例如,”324″被轉換為324 通過ToString()把值轉化成字串:
引數 結果 undefined “undefined” null “null” boolean “true” 或者 “false” number 數字作為字串。比如,”1.765″ string 無需轉換
六、從例項中理解
- 運算元其一為字串(String)
/**
* 運算元其一為字串(String)
*/
console.log('12'+1); // 121
console.log('abc'+'def'); // abcdef
console.log('1'+true); //1true
console.log('1'+undefined); //1undefined
console.log('1'+null); //1null
運算元其一為字串,字串的拼接運算。
- 運算元其一為數字(Number)
/**
* 運算元其一為數字(Number)
*/
console.log(1+1); // 2
console.log(1+'def'); // 1def
console.log(1+true); //2
console.log(1+undefined); //NaN
console.log(1+null); //1
1+'def'為運算元其一為字串情況,其餘為在沒有字串情況下,運算元其一為數字,做型別轉換後相加。
- 數字(Number)/字串(String)以外的原始型別相加
/**
* 數字(Number)/字串(String)以外的原始型別相加
*/
console.log(true+true); // 2
console.log(true+null); // 1
console.log(true+undefined); //NaN
console.log(undefined+null); //NaN
console.log(undefined+undefined); //NaN
console.log(null+null); //0
當數字與字串以外的,其他原始資料型別直接使用加號運算時,就是轉為數字再運算,這與字串完全無關。
- 空陣列 + 空陣列
console.log([] + []); //""
兩個陣列相加,左右運算元先呼叫valueOf(),返回陣列本身,呼叫toString(),返回原始資料型別,即空字串,作連線操作,得到一個空字串。
- 空物件 + 空物件
console.log({} + {}); //"[object Object][object Object]"
兩個物件相加,左右運算元先呼叫valueOf(),返回物件本身,呼叫toString(),返回原始資料型別,即物件字串[object Object],作連線操作,得到字串[object Object][object Object]
console.log({}+{})得到的這樣的結果,但是,在有些瀏覽器例如Firefox、Edge控制檯直接輸入{}+{},會得到NaN,因為瀏覽器會把{} + {}直譯為相當於+{}語句,因為它們會認為以花括號開頭({)的,是一個區塊語句的開頭,而不是一個物件字面量,所以會認為略過第一個{},把整個語句認為是個+{}的語句,也就是相當於強制求出數字值的Number({})函式呼叫運算,相當於Number("[object Object]")運算,最後得出的是NaN。如果加上圓括號({}) + {},則可以避免這樣的問題。
- 空物件 + 空陣列
console.log({} + []); //"[object Object]"
空物件和空陣列相加,左右運算元先呼叫valueOf(),返回物件陣列本身,呼叫toString(),返回原始資料型別,即物件字串[object Object]和"",作連線操作,得到字串[object Object]
直接console.log得到的都是一樣的值,但是直接在瀏覽器控制檯輸入:
> {} + []
0
> [] + {}
"[object Object]"
{} + []相當於+[]語句,也就是相當於強制求出數字值的Number([])運算,相當於Number("")運算,最後得出的是0數字。
- Date物件
console.log(1 + (new Date())); //"1Tue Aug 14 2018 21:18:24 GMT+0800 (中國標準時間)"
Date物件首選型別String,先呼叫toString(),得到字串做字串連線運算。
要得出Date物件中的valueOf返回值,需要使用一元加號(+),來強制轉換它為數字型別,例如以下的程式碼:
console.log(+new Date());
1534298171747
Symbols型別
ES6中新加入的Symbols資料型別,它不算是一般的值也不是物件,它並沒有內部自動轉型的設計,所以完全不能直接用於加法運算,使用時會報錯。+[]/+{}
console.log(+[]); // 0
console.log(+{}); // NaN
console.log(+null); //0
console.log(+true); //1
console.log(+undefined); //NaN
一元加號運算時,唯一的運算元相當於強制求出數字值的Number([])運算。
相關文章
- Numpy 加法運算,opencv 加法運算,影像的融合OpenCV
- 使用位運算進行加法運算
- javascript怎麼實現算術加法運算JavaScript
- Java 數學運算與條件語句全解析Java
- opencv入門系列教學(六)影像上的算術運算(加法、融合、按位運算)OpenCV
- JavaScript + 加法運算子JavaScript
- JavaScript (+) 加法運算子JavaScript
- C語言程式設計-長整數加法運算C語言程式設計
- 加法小計算
- 巧用JS位運算JS
- 大數運算—大數加法、減法、乘法、除法詳解
- FPGA定點小數計算(Verilog版)第一篇——加法運算FPGA
- JS常用陣列操作全解析JS陣列
- JS中的位運算JS
- [Python影象處理] 五.影象融合、加法運算及影象型別轉換Python型別
- js 方法(運算元組為主JS
- 7-2 一元多項式的乘法與加法運算 (20 分)
- 橢圓曲線加法原理計算
- 詳解線性結構 —— 一元多項式的乘法與加法運算
- spark的基本運算元使用和原始碼解析Spark原始碼
- js運算元組中資料排列組合JS
- 演算法小記·不用四則運算做加法演算法
- PyThon程式設計必看!python加法運算子的用法Python程式設計
- java基礎(四) java運算順序的深入解析Java
- Dive into TensorFlow系列(2)- 解析TF核心抽象op運算元抽象
- opencv 開運算、閉運算OpenCV
- 圖文剖析 big.js 四則運算原始碼JS原始碼
- 全面總結 JS 中浮點數運算問題JS
- ConstraintLayout 全解析AI
- Immer 全解析
- HTTP全解析HTTP
- Vuex全解析Vue
- Choreographer全解析
- 使用運算元控制公式運算公式
- Kotlin 運算子詳解:算術、賦值、比較與邏輯運算子全解析Kotlin賦值
- js json解析JSON
- 算力時代的高品質全光運力網路
- 高效能運算知識: 深度解析Lustre體系結構