ECMAScript 數據類型之Number類型

前言

本文為【JSRedBook】中數據類型的篇章, 主要講述 ECMAScript 的 6 種簡單數據類型(原始類型)中的其中一種:Number 類型;主要說明五個方面:Number定義浮點值值的范圍NaN與 數值轉換

Number 類型:

Number 類型使用 IEEE 754 格式表示整數和浮點值(在某些語言中也叫雙精度值),不同的數值類型相應地也有不同的數值字面量格式。

練習場景

最基本的數值字面量格式是十進制整數,如下:

 const intNum = 42;

其他進制

整數也可以用八進制(以 8 為基數)或十六進制(以 16 為基數)字面量表示

八進制

對於八進制字面量,第一個數字必須是零(0),然後是相應的八進制數字(數值 0~7),如果字面量中包含的數字超出瞭應有的范圍,就會忽略前綴的零,後面的數字序列會被當成十進制數。

下面是幾個例子:

 let octalNum1 = 070; // 八進制的 56 
 let octalNum2 = 079; // 無效的八進制值,當成 79 處理
 let octalNum3 = 08; // 無效的八進制值,當成 8 處理

註意: 八進制字面量在嚴格模式下是無效的,會導致 JavaScript 引擎拋出語法錯誤

原因是ECMAScript 2015 或 ES6 中的八進制值通過前綴 0o 來表示;嚴格模式下,前綴 0 會被視為語法錯誤,如果要表示八進制值,應該使用前綴 0o

十六進制

要創建十六進制字面量,必須讓真正的數值前綴 0x(區分大小寫),然後是十六進制數字(09 以 及 AF),十六進制數字中的字母大小寫均可

下面是幾個例子:

 let hexNum1 = 0xA; // 十六進制 10 
 let hexNum2 = 0x1f; // 十六進制 31 

使用八進制和十六進制格式創建的數值在所有數學操作中都被視為十進制數值。

註意: 由於 JavaScript 保存數值的方式,實際中可能存在正零(+0)和負零(-0);其中正零和負零在所有情況下都被認為是等同的

浮點值

要定義浮點值,數值中必須包含小數點,而且小數點後面必須至少有一個數字,雖然小數點前面不是必須有整數,但推薦加上

下面是幾個例子:

 const floatNum1 = 1.1;
 const floatNum2 = 0.1;
 const floatNum3 = .1; // 有效 但不推薦

因為存儲浮點值使用的內存空間是存儲整數值的兩倍,所以 ECMAScript 總是想方設法把值轉換為整數。在小數點後面沒有數字的情況下,數值就會變成整數。類似地,如果數值本身就是整數,隻是小數點後面跟著 0(如 1.0),那它也會被轉換為整數.

下面是幾個例子:

 let floatNum1 = 1.; // 小數點後面沒有數字,當成整數 1 處理
 let floatNum2 = 10.0; // 小數點後面是零,當成整數 10 處理

科學計數法

科學記數法用於表示一個應該乘以10 的給定次冪的數值,對於非常大或非常小的數值浮點值可以用科學記數法來表示。

ECMAScript 中科學記數法的格式要求是一個數值(整數或浮點數)後跟一個大寫或小寫的字母 e,再加上一個要乘的 10 的多少次冪。如下:

 let floatNum = 3.125e7; // 等於 31250000 

解法:3.125 作為系數,乘以 10 的 7 次冪,正常也直接書寫出來,隻是用科學計數法會更加簡潔。

小數值

科學記數法也可以用於表示非常小的數值

默認情況下,ECMAScript 會將小數點後至少包含 6 個零的浮點值轉換為科學記數法

例如,0.0000003 用科學記數法可以表示為 3e-7 ,又例如 0.000000000000000 03 會被轉換為 3e-17;

不清晰的話請看下圖:

浮點值精確度

浮點值的精確度最高可達 17 位小數,但在算術計算中遠不如整數精確。

舉例一個坑, 0.1 加 0.2 得到的不是 0.3,而是 0.30000000000000004,如下:

 /* 這裡檢測兩個數值之和是否等於 0.3 */
 ​
 if (a + b == 0.3) { // 別這麼幹! 
  console.log("You got 0.3."); 
 } // 並不等於 0.3 因此if中的語句不會執行

如果兩個數值分別是 0.05 和 0.25,或者 0.15 和 0.15,那沒問題;但如果是 0.1 和 0.2,如前所述,測試將失敗。由於這種微小的舍入錯誤,導致很難測試,因此永遠不要測試某個特定的浮點值。

註意: 之所以存在這種舍入錯誤,是因為使用瞭 IEEE 754 數值,這種錯誤並非 ECMAScript 所獨有,其他使用相同格式的語言也有這個問題。

值的范圍

由於內存的限制,ECMAScript 並不支持表示這個世界上的所有數值

最大值與最小值

ECMAScript 可以表示的最小數值保存在 Number.MIN_VALUE 中,這個值在多數瀏覽器中是 5e-324;可以表示的最大數值保存在 Number.MAX_VALUE 中,這個值在多數瀏覽器中是1.7976931348623157e+308。

小知識: 使用 Number.NEGATIVE_INFINITY(負無窮大) 和 Number.POSITIVE_INFINITY(正無窮大) 也可以獲取正負 Infinity

Infinity

如果某個計算得到的數值結果超出瞭 JavaScript 可以表示的范圍,那麼這個數值會被自動轉換為一個特殊的 Infinity(無窮)值;任何無法表示的負數以 -Infinity(負無窮大)表示,任何無法表示的正數以 Infinity(正無窮大)表示。

isFinite() 函數

如果計算返回正 Infinity 或負 Infinity,則該值將不能再進一步用於任何計算

這是因為 Infinity 沒有可用於計算的數值表示形式,如果要確定一個值是不是有限大(即介於 JavaScript 能表示的最小值和最大值之間),可以使用 isFinite()函數,如下所示:

 let result = Number.MAX_VALUE + Number.MAX_VALUE; 
 console.log(isFinite(result)); // false 

註意: 雖然超出有限數值范圍的計算並不多見,但總歸還是有可能的;因此在計算非常大或非常小的數值時,有必要檢測一下計算結果是否超出范圍。

NaN

有一個特殊的數值叫 NaN,意思是 Not a Number(不是數值),用於表示本來要返回數值的操作失敗瞭(而不是拋出錯誤)。

練習場景

比如,用 0 除任意數值在其他語言中通常都會導致錯誤,從而中止代碼執行。

但在 ECMAScript 中,0、 +0 或 -0 相除都會返回 NaN

 console.log( 0/0 ); // NaN 
 console.log( -0/+0 ); // NaN 

如果分子是非 0 值,分母是有符號 0 或無符號 0,則會返回 Infinity 或 -Infinity

 console.log( 5/0 );  // Infinity 
 console.log( 5/-0 );  // -Infinity 

NaN特性

任何涉及 NaN 的操作始終返回 NaN(如 NaN/10),並且 NaN 不等於包括 NaN 在內的任何值。

例如,下面的比較操作會返回 false:

 console.log(NaN == NaN); // false 

isNaN()函數

ECMAScript 提供瞭 isNaN()函數用於判斷檢測數值。

用法: 該函數接收一個參數,可以是任意數據類型,然後判斷這個參數是否 “不是數值”。

性質: 把一個值傳給 isNaN() 後,該函數會嘗試把它轉換為數值;某些非數值的值可以直接轉換成數值,如字符串"10"或佈爾值;任何不能轉換為數值的值都會導致這個函數返回true

語法: isNaN(vallue) 必傳,參數為要檢測的值

列舉瞭5種常見場景,如下:

 /* isNaN:[潛意思]你是不是非數值或者不能轉數值呀 */
 ​
 console.log(isNaN(NaN)); // true 
 console.log(isNaN(10)); // false,10 是數值
 console.log(isNaN("10")); // false,可以轉換為數值 10 
 console.log(isNaN("blue")); // true,不可以轉換為數值
 console.log(isNaN(true)); // false,可以轉換為數值 1 

解釋: 首先測試的是 NaN 本身,因為 Not a Number ,顯然會返回 true;接著測試瞭數值 10

和字符串"10",都返回 false,因為它們的數值都是 10;字符串"blue"不能轉換為數值,因此函數返

回 true;佈爾值 true 可以轉換為數值 1,因此返回 false;

小知識: 雖然不常見,但 isNaN()可以用於測試對象。

機制: 首先會調用對象的 valueOf()方法,然後再確定返回的值是否可以轉換為數值;如果不能,再調用 toString() 方法,並測試其返回值。

數值轉換

有 3 個函數可以將非數值轉換為數值:Number()parseInt()和 parseFloat()

Number()

Number()是轉型函數,可用於任何數據類型。

語法

Number(object) 參數可選,為一個 JavaScript 對象;如果沒有提供參數,則返回0。

Number()函數轉換規則:

  • 佈爾值,true 轉換為 1,false 轉換為 0
  • 數值,直接返回
  • null,返回 0
  • undefined,返回 NaN

字符串,應用以下規則:

  • 如果字符串包含數值字符,包括數值字符前面帶加、減號的情況,則轉換為一個十進制數值。
  • 因此,Number("123")返回 123,Number("011") 返回 11(忽略前面的零
  • 如果字符串包含有效的浮點值格式如"1.1",則會轉換為相應的浮點值(忽略前面的零)。
  • 如果字符串包含有效的十六進制格式如"0xf",則會轉換為與該十六進制值對應的十進制整

數值:

如果是空字符串(不包含字符),則返回 0

如果字符串包含除上述情況之外的其他字符,則返回 NaN

對象,調用 valueOf()方法,並按照上述規則轉換返回的值。如果轉換結果是 NaN,則調用toString()方法,再按照轉換字符串的規則轉換

Number()函數場景練習

從不同數據類型到數值的轉換有時候會比較復雜,看一看 Number() 的轉換規則就知道瞭

下面是幾個具體的例子:

 Number("一二三") // NaN
 Number(undefined) //NaN
 Number("001.01") // 1.01
 Number("") // 0
 Number(null) // 0

可以看到,字符串 "一二三" 轉換之後是 NaN,因為它找不到對應的數值;undefined轉換後為NaN;字符串 001.101 轉換後是 1.01,因為前面的零被忽略瞭;最後空字符串null轉換後都是 0

parseInt()

parseInt() 函數會解析一個字符串,並返回一個整數,並且更專註於字符串是否包含數值模式。

語法

parseInt(string, radix)

參數1必選,為要被解析的字符串。

參數2可選,表示要解析的數字的基數;該值介於 2 ~ 36 之間。

parseInt()函數轉換規則

  • 字符串最前面的空格會被忽略,從第一個非空格字符開始轉換
  • 如果第一個字符不是數值字符、加號或減號,parseInt()立即返回 NaN 這意味著空字符串也會返回 NaN(這一點跟 Number()不一樣,它返回 0)。
  • 如果第一個字符是數值字符、加號或減號,則繼續依次檢測每個字符,直到字符串末尾,或碰到非數值字符;如, "1234blue" 會被轉換為 1234,因為 "blue" 會被完全忽略;類似地,"22.5"會被轉換為 22,因為小數點不是有效的整數字符。

進制轉換

假設字符串中的第一個字符是數值字符,parseInt() 函數也能識別不同的整數格式(十進制、八進制、十六進制);換句話說,如果字符串以"0x"開頭,就會被解釋為十六進制整數;如果字符串以"0"開頭,且緊跟著數值字符,在非嚴格模式下會被某些實現解釋為八進制整數

parseInt()函數練習場景

隻有一個參數的場景

請看下面幾個例子:

 parseInt("22")  // 22
 parseInt("21.33") // 21
 parseInt(" 34 age 43 ")  // 34
 parseInt("Are you 99 ?")  // NaN
 parseInt("0010") // 10

兩個參數的場景

不同的數值格式很容易混淆,因此 parseInt() 也接收第二個參數,用於指定底數(進制數)。如果知道要解析的值是十六進制,那麼可以傳入 16 作為第二個參數,以便正確解析:

 parseInt("0xAF", 16); // 175 
 parseInt("33",8) // 102

事實上,如果提供瞭十六進制參數,那麼字符串前面的"0x"可以省掉:

 let num1 = parseInt("AF", 16); // 175 
 let num2 = parseInt("AF"); // NaN 

在這個例子中,第一個轉換是正確的,而第二個轉換失敗瞭。區別在於第一次傳入瞭進制數作為參數,告訴 parseInt() 要解析的是一個十六進制字符串。而第二個轉換檢測到第一個字符就是非數值字符,隨即自動停止並返回 NaN

通過第二個參數,可以極大擴展轉換後獲得的結果類型。比如:

 let num1 = parseInt("10", 2); // 2 按二進制解析
 let num2 = parseInt("10", 8); // 8 按八進制解析
 let num3 = parseInt("10", 10); // 10,按十進制解析
 let num4 = parseInt("10", 16); // 16,按十六進制解析

因為不傳底數參數相當於讓 parseInt() 自己決定如何解析,所以為避免解析出錯,建議始終傳給它第二個參數。

註意: 大多數情況下解析的應該都是十進制數,此時第二個參數就要傳入10.

parseFloat()

parseFloat() 函數可解析一個字符串,並返回一個浮點數

從下標 0 開始檢測每個字符,解析到字符串末尾或者解析到一個無效的浮點數值字符為止;與parseInt()不同的是它第一次出現的小數點是有效的,但第二次出現的小數點就無效瞭,此時字符串的剩餘字符都會被忽略

語法

parseFloat(string) 參數必選,為要被解析的字符串。

parseFloat()函數轉換規則

parseFloat()函數的另一個不同之處在於,它始終忽略字符串開頭的零。

這個函數能識別前面討論的所有浮點格式,以及十進制格式(開頭的零始終被忽略),十六進制數值始終會返回 ;因為 parseFloat() 隻解析十進制值,因此不能指定底數。

parseInt()函數練習場景

下面是幾個示例:

 parseFloat("1234blue"); // 1234,按整數解析
 parseFloat("0xA"); // 0 
 parseFloat("22.5"); // 22.5 
 parseFloat("0022.34.5"); // 22.34 
 parseFloat("3.125e7"); // 31250000 

註意: 如果字符串表示整數(沒有小數點或者小數點後面隻有一個零),則 parseFloat() 返回整數

總結

Number類型為JavaScript中唯一的數字類型,整數的精度最多為15位

  • 進制: JavaScript 會把數值常量解析,若前綴為 0,則解釋為八進制數;如果前綴為 "0x",則解釋為十六進制數
  • 浮點值: 要定義浮點值,數值中必須包含小數點,而且小數點後面必須至少有一個數字
  • 科學記數法: 用於表示一個應該乘以10 的給定次冪的數值,較大的數值使用它會更加簡潔
  • 無窮: 最大值(Infinity)表示 1.7976931348623157e+308,最小值表示 5e-324
  • NaN: 意思是 Not a Number(不是數值),可以把 Number 對象設置為該值,來指示其不是數字值;任何涉及 NaN 的操作始終返回 NaN,並且 NaN 不等於包括 NaN 在內的任何值
  • Number()適用於向多樣類型轉型為數值型
  • parseInt()適用於將字符串轉換成浮點數
  • parseFloat()適用於將字符串轉換成整型數字

到此這篇關於 ECMAScript 數據類型之Number類型的文章就介紹到這瞭,更多相關 ECMAScript  Number類型內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: