這篇文章為大家帶來了關於javascript的相關知識,其中主要介紹了關於數字類型的相關內容,JavaScript中存在兩種表示數字的類型:Number和BigInt類型,下面一起來看一下,希望對大家有幫助。
【相關推薦:javascript影片教學、web前端】
JavaScript
中存在兩種表示數字的型別:
Number
類型,也就是常規意義上的數字類型,以64
位元的IEEE-754
格式存儲,屬於“雙精度浮點數”,截至目前,我們接觸到的數字全部都是Number
類型;
BigInt
類型,表示任意長度的整數,通常情況下我們用不到它們,除非表示2 53至-2 53之外的數字,此類專業資料類型我們會在後面的章節詳細介紹;
數字的寫法本身很簡單,但是JavaScrpt
有很多方便快速的語法糖供我們使用,好好學習這些語法糖不僅能夠提高我們的程式碼閱讀能力,同時可以提高我們程式碼的高級感(逼格)。
十進制的數字最簡單了,幾乎每篇文章我們都多多少少會使用,例如我們創建一個變量,並存儲100
億:
let tenbillion = 10000000000;
雖然操作起來非常簡單,但是有一個問題:很難數清楚1
後面到底有幾個0
,如果我們寫的是轉賬代碼,錯個0
可能會傾家蕩產。
此時,我們可以使用_
作為分隔符,如下:
let tenbillion = 10_000_000_000;
上述程式碼就可以非常明白的數清0
的個數,顯然是最優解!
這裡的底線_
就是JavaScript
的一個語法糖,在執行過程中會被引擎忽略,以上兩種寫法效果完全相同,但是閱讀體驗相差很大。
清奇腦迴路
有些童鞋就要問了,我從小都是4
個0
一組的,為啥非要3
個0
分一組呢?所以,我們可以寫成下面的方式,同樣沒有問題:
let tenbillion = 100_0000_0000;
亦或者寫成這樣:
let tenbillion = 1_0000_0000_00;
這裡我想表達的是,不論你採用哪種分割方式,都是不影響數字本身的大小的,快想一個逼格最高的方式吧!
雖然使用_
可以優雅的分割很多0
,但是在實際生活中,我們一般不這麼寫,例如我們常常將10000000000
寫成“100億”,這樣就可以省略很多0
,從而降低犯錯的可能性。
JavaScript
同樣提供了一種省略0
的寫法,我們可以用字母e
後面跟個數字表示0
的個數,舉個栗子:
let tenbillion = 1e10;//100億,1後面10個0console.log(3.14e9);//3140000000,後面7個0,此處疑惑可往下看
上述程式碼的理解非常簡單, e10
可以理解為1_0000_0000_00
,也就是1
後面10
個0
,所以我們可以認為:
1e10 === 1 * 1_0000_0000_00;//e10表示1後面10個03.14e9 === 3.14 * 1_000_000_000;//e9表示1後面9個0
我們也可以使用這種方法表示非常小的數字,例如1
奈米:
let nm = 0.000000001;//單位(米)
由於0
的個數過多,我們也可以使用_
分割:
let nm = 0.000_000_001;
當然,也可以用e
的方式省略掉所有的0
,如下:
let nm = 1e-9;//1的左邊9個0,包括小數點前面的那個
換句話說, e-9
的意思就是1 -9 ,也就是1/1000_000_000
,所以下面的等式是成立的:
1e-9 === 1 / 1_000_000_000;3.14e-8 === 3.14 / 1_000_000_00;
十六進位是程式設計常用的格式,例如表示顏色、編碼等,我們可以在普通數字前加0x
表示十六進位數字:
let hex = 0xff;//255,不區分大小寫,0xFF是相同的
二進位數字使用0b
開頭:
let bin = 0b1011;//11
八進制數字使用0o
開頭:
let oct = 0o777;//511
這種簡單的寫法只支援這三種特殊類型,至於其他進位的數字可以使用特殊的函數來產生( parseInt
)。
toString
方法可以把數字轉為對應進位base
的字串形式。
舉個栗子:
let num = 996; console.log(num.toString(8));//轉為8進位字串console.log(num.toString(16));//轉為16進位字串console.log(num.toString( 32));//轉為32進位字串
程式碼執行結果如下:
base
的範圍可以從2
到36
,如果不填預設為10
。
請注意,如果使用數字直接呼叫toString
方法,在有些情況下需要是應用兩個.
,舉例如下:
console.log(123.toString(8));//Error,語法錯誤console.log(123..toString(8));//正確,173
數字後面有兩個.
,這是因為在JavaScript
中數字後面的第一個.
被認為是小數點,第二個點才是調用函數的.
。
如果是小數就不存在這個問題,舉個栗子:
console.log(3.14.toString(8));
亦或者,我們使用小括號可以避免使用兩點,舉個栗子:
console.log((123).toString(8));//'173
舍入是數字最常用的操作之一,通常包括:
向下取整, Math.floor(num)
console.log(Math.floor(3.14));//3 console.log(Math.floor(9.99));//9 console.log(Math.floor(-3.14));//-4 console.log(Math.floor(-9.99));//-10
不遵循四捨五入原則,直接取小於等於目前數值的最近整數。
向上取整, Math.ceil(num)
console.log(Math.ceil(3.14));//4 console.log(Math.ceil(9.99));//10 console.log(Math.ceil(-3.14));//-3 console.log(Math.ceil(-9.99));//-9
不遵循四捨五入原則,直接取大於等於目前數字的最近整數。
就近取整, Math.round(num)
console.log(Math.round(3.14));//3 console.log(Math.round(9.99));//10 console.log(Math.round(-3.14));//-3 console.log(Math.round(-9.99));//-10
遵循四捨五入原則,取距離目前數字最近的整數。
移除小數, Math.trunc(num)
console.log(Math.trunc(3.14));//3 console.log(Math.trunc(9.99));//9 console.log(Math.trunc(-3.14));//-3 console.log(Math.trunc(-9.99));//-9
直接移除小數點後面的數字,取整數位。 IE瀏覽器不支援這個方法
對比以上四種方法:
Math.floor | Math.ceil | Math.round | Math.trunc | |
---|---|---|---|---|
3.14 | 3 | 4 | 3 | 3 |
9.99 | 9 | 10 | 10 | 9 |
-3.14 | -4 | -3 | -3 | -3 |
-9.99 | -10 | -9 | -10 | -9 |
上述方法只是簡單的把小數捨入成了整數,在有些情況下,我們需要特定精度的小數,例如取圓周率後4
位該怎麼辦呢?
有兩種方法:
數學乘除計數
let pi = 3.1415926;console.log(Math.round(pi * 10000) / 10000);//3.1416
上述程式碼先將pi
乘以10000
,然後取整,再除以10000
,從而得到了符合精度要求的結果。但是,這麼做看起啦呆呆的, JavaScript
為我們提供了更簡單的方法。
toFixed(n)
let pi = 3.1415926;console.log(pi.toFixed(4));//3.1416
以上程式碼看起來輸出上沒有什麼問題,實際上, toFixed
回傳的是一個字串,如果我們需要一個數字類型,要轉換一下才行,可以使用單目運算子+ pi.toFixed(4)
。
另外,如果小數的尾數長度不夠, toFixed
會在後面補上'0'
:
let num = 3.1;console.log(num.toFixed(9));
程式碼執行結果如下:
這也側面證明了toFixed
的回傳值是一個字串,否則0
會被省略。
浮點數表示在許多情況下總是存在偏差
在電腦內部,浮點數依IEEE-754
標準表示,其中單精度浮點數32
位,雙精度浮點數64
位。在雙精確度浮點數中, 1
位元用於表示符號, 52
位元用於儲存有效數字, 11
位元儲存小數點的位置。
雖然64
位已經可以表示非常大的數字了,但是仍然存在越界的可能,例如:
let bigNum = 1e999;console.log(bigNum);//Infinity
越過做最大值的數字將變成Infinity
(無窮),這樣就失去了原有數字的大小,屬於偏差的一種。
還有一種偏差,需要我們學習:
console.log(0.1+0.2 === 0.3);//falseconsole.log(0.1 + 0.2);
程式碼執行結果如下:
沒錯, 0.1 + 0.2
的結果不是0.3
,而是一堆0
後面加4
。
這種偏差是非常致命的,尤其在商城、銀行工作場景中,即使是一個非常小的偏差,在高流水場景下都會失去無盡的財富。
曾經聽過一個銀行員工透過剋扣工人工資,盜取百萬財富的故事,每個員工的薪水只剋扣2毛!
我想這種事情發生在我身上,我肯定發現不了,所以無時無刻的精確是多麼的重要。
這個故事不知真假~~
先以我們常見的十進制為例,我們都知道,小數中存在兩個奇葩,一個叫無限循環小數,另一個叫無限不循環小數,例如1/3
就是一個無限循環小數0.3333333(3)
,而圓周率就是一個無限不循環小數。無限意味著無法用數字清楚的描述這個數字的大小,我們能寫出來的都是不精確的。
二進制同樣存在一些無限循環的數字,不同的是在十進制中0.1
這種看起啦很簡單的數字,在二進制中卻是無限循環小數。
舉個例子:
let x = 0.1;console.log(x.toFixed(20));
程式碼執行結果如下:
是不是覺得不可思議呢?我們只是簡單的創建了一個變數並賦值0.1
,然後取小數點後20
位,卻得到了一個匪夷所思的結果。
如果我們換一個角度或許會更容易理解這種現象,在十進制中,任何整數除以10
或10
整數次方都是正常的精確的數字,例如1/10
或996/1000
。但是,如果以3
為除數,就會得到循環的結果,例如1/3
。
這種描述如果換到二進位上,同樣是成立的。
在二進位中,任何整數除以2
或2
的整數次方都是正常的精確的數字,但是,如果以10
為除數,就會得到無限循環的二進制數。
所以,我們就可以得出結論,二進制數字無法精確表示0.1
和0.2
就像十進制沒有辦法描述1/3
一樣。
注意:
這種數據上的偏差並非JavaScript的缺陷,像是PHP、Java、C、Perl、Ruby都是同樣的結果。
捨入
在展示一個無限循環小數的時候,我們可以直接使用toFixed
方法對小數進行舍入,該方法直接傳回字串,非常方便用於展示價格。
0.3.toFixed(2);//0.30
使用小單位
另外一種方式是,我們可以使用較小的單位來計算諸如價格、距離,例如採用分而不是元計算總價,實際上很多交易網站都是這麼做的。但這種方法只是降低小數出現的次數,並沒有辦法完全避免小數的出現。
JavaScript
數字中有兩個特殊值: Infinity
和NaN
。
如何判斷一個數字是不是正常數字呢?
我們可以使用兩個方法:
isFinite(val)
此函數會將參數val
轉為數字類型,然後判斷這個數字是否是有窮的,當數字不是NaN
、 Infinity
、 -Infinity
時傳回true
。
console.log(isFinite(NaN));//falseconsole.log(isFinite(Infinity));//falseconsole.log(isFinite(3));//trueconsole.log(isFinite('12'));// true
程式碼執行結果如下:
由於無法轉為數字的字串會被轉為NaN
,所以我們可以使用isFinite
方法判斷字串是不是數字字串:
console.log(isFinite('xxxx'));//falseconsole.log(isFinite('Infinite'));//falseconsole.log(isFinite(' '));//true,空串轉為0
程式碼執行結果如下:
isNaN(val)
當val
為NaN
或無法轉為數字的其他值時,傳回true
。
console.log(isNaN(NaN));//trueconsole.log(isNaN('Infinite'));//true
程式碼執行結果:
為什麼要使用isNaN
函數而不是直接判讀呢?
例如:
console.log(NaN === NaN);//false
程式碼執行結果如下:
這是因為NaN
不等於任何數,包括自己。
Object.is(a,b)
可以判斷參數a
和b
是否相等,若相等回傳true
,否則回傳false
,它的結果只有三種情況:
可以比較NaN
console.log(Object.is(NaN,NaN));//true
程式碼執行結果:
0 和-0
console.log(Object.is(0,-0));//false
程式碼執行結果:
在電腦內部,正負使用0
和1
表示,由於符號不同,導致0
和-0
其實是不同的,二者的表示方式也不一樣。
其他
其他比較情況和a === b
完全相同。
parseInt
和parseFloat
可以把字串轉為數字,與+
、 Number
不同的是,二者的限制更為鬆散。例如,像"100¥"
這樣的字串使用+
和Number
必然返回NaN
,而parseInt
和parseFloat
卻能輕鬆應對。
舉個例子:
console.log(+"100¥");console.log(parseInt("100¥"));console.log(parseFloat("12.5¥"));
程式碼執行結果:
parseInt
和parseFloat
會從字串中讀取數字,直到無法讀取為止。二者特別適合處理像"99px"
、 "11.4em"
這種數字開頭的字串情況,但是對於其他字元開頭的字串則傳回NaN
。
console.log(parseInt('ff2000'));//NaN
但是,我們發現ff2000
其實是一個十六進位的數字字串, parseInt
同樣可以處理這種情況,不過需要加入一個進位參數。
舉個例子:
console.log(parseInt('FF2000',16)); //16719872 console.log(parseInt('0xFF2000',16)); //16719872 console.log(parseInt('nnnnnn',36)); //1430456963
程式碼執行結果:
內建的Math
物件中包含了許多我們常用到的常數和方法,以下僅舉例介紹常用的幾個:
Math.PI
圓周率Π
是無限不循環的常數,我們可以用Math.PI
來代替:
console.log(Math.PI);
Math.random()
產生一個位於區間[0,1)
的隨機數:
console.log(Math.random());console.log(Math.random());
如果我們需要一個特定區間內的隨機數,可以乘以特定的值,然後取整哦。
Math.pow(a,b)
算a b ,舉例如下:
console.log(Math.pow(2,3));//8
Math.max()/Math.min()
從任意數量的參數中選出一個最大值/最小值:
console.log(Math.max(1,2,3,4,5));//5console.log(Math.min(1,2,3,4,5));//1