1. 程式人生 > 其它 >JS紅寶書學習-第3章 語言基礎 --資料型別_Number

JS紅寶書學習-第3章 語言基礎 --資料型別_Number

3.4 資料型別

1.Number型別
ES中Number型別使用的是IEEE754格式表示整數和浮點數,不同數值型別相應地也有不同的數值字面量格式
基本的數值字面量格式是十進位制整數,直接寫出來即可:

let intNum = 55; // 整數

整數也可以使用八進位制或十六進位制字面量表示。對於八進位制字面量,第一個數字必須是零(0),然後是相應的八進位制數字(數值0~7)。如果包含的數字超出了應有的範圍,就會忽略字首的零,後面數字序列被當成十進位制。

let octalNum1 = 070; // 八進位制的56
let octalNum2 = 079; // 無效的八進位制,忽略字首變為79
let octalNum3 = 08;  //  無效的八進位制忽略字首變為8

八進位制的字面量在嚴格模式下是無效的,會丟擲語法錯誤。在es6中八進位制可以用字首0o來達字面量。

對於十六進位制字面量,必須以0x作為數值字首,然後是16進位制數字(09以及AF)。十六進位制數字中的字母大小寫均可。

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

使用八進位制與十六進位制核實建立的數值在所有數學操作中都被視為十進位制數值。

js中存在正零(+0)和負零(-0)。它倆在任何場景都被被認為是相同的。

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

let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 =.1;	// 這個也有效,但是不推薦

因為浮點數使用的記憶體是整數的兩倍,所以es總會把值轉換為整數。在小數點後面沒有數字的情況下會直接轉換為整數,同樣如果數值本身是整數,只是小數點後面跟了一個0,name也會轉換為整數。

let floatNum1 = 1.;	// 小數點後面沒數字,當成整數1處理
let floatNum2 = 1.0;	// 小數點後面是0,當成整數1處理。

對於非常大或者非常小的數值,浮點值可以用科學計數法來表示。科學記數法用於用於表示一個應該乘以10的給定次冪的數值。es中的科學記數法的格式是要求一個數值(整數或者浮點數)後面跟一個大寫或者小寫的e,在加上一個要乘10的多少次冪。

let floatNum = 3.3333e4;	// 等於33333

雖然我們也可以直接寫上floatNum的值為33333,但是這樣會更加的簡潔準確。

科學記數法也可以用作表達非常小的數值,例如:

let floatNum = 3e-6; // 0.000003

預設情況下,es會將小數點至少包含6個零的浮點值轉換為科學記數法。(這個地方很有趣,我在之前做練習的時候在控制檯輸入3e-16一直返回3e-16,我還以為我寫錯了,看完才明白。。。)
浮點值得精準度最高可達17位小數,但是算數計算中遠不如整數精確。例如,0.1+0.2得到的就不是0.3,而是0.30000000000000004。由於這種微小的舍入錯誤,導致很難測定特定的浮點值,但是你說氣不氣有些值它好用,計算正確。所以以防萬一,不要測試某個特定的浮點值。

let a = 0.1, b = 0.2, c = 0.3;
if(a + b == c){ // 你說奇不奇怪
  console.log("我是你得不到的0.3");
}

if(a + c == 0.4){ // 我又好使了
  console.log("為啥上面的兄弟不好使");
}

注意之所以存在這種舍入鎖霧,是因為使用了IEEE754數值,其餘使用相同格式的也有這個問題。(這個問題我看到很多不同文章來說明原因,大體是計算機計算數值的原因,當我們需要精度高的浮點數可以使用BigNumber來確保準確~~~)

1.2 值的範圍
由於記憶體限制,es並不支援世界上的所有數值,es可以表示的最小數值儲存在Number.MIN_VALUE中,大多瀏覽器為5e-324;如果某個計算得到數值超出了js的表示範圍,那麼就會被轉換為一個特殊的Infinity(無窮)值。任何無法表示的附屬以-Infinity表示,正數以Infinity表示。
如果計算返回正Infinity或-Infinity,則該值不能再進一步用於任何計算。這是因為Infinity沒有可用於計算的數值表示形式。可以使用isFinit()函式來判斷值是否為有限性的值。

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

1.3 NaN
在Number中有一個特殊的值NaN,意思是”不是數值“,用於表示本來要返回數值的操作失敗了,比如,用0除任意數值的其他語言通常都會導致錯誤,從而結束程式碼執行,但是ES中,0,+0,-0相處都會返回NaN。

conosle.log(0/0);  // NaN

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

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

NaN有幾個特殊的屬性。首先,任何涉及NaN的操作始終返回NaN。其次,NaN不等於包括與NaN在內的任何值。

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

為此,ES提供了isNaN()函式。該函式接受一個引數,可以是任意資料型別,然後判斷這個引數是否為”不是數值“。把一個值傳給isNaN()後,該函式會嘗試把它轉換為數值,某些非數值的值可以直接轉換成數值,如字串”1“或者布林值,任何不能轉換為數值的值都會返回true。

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

注意:isNaN()可以用來測試物件,此時,首先會呼叫物件的valueOf()方法,然後再確定返回的值時候可以轉換為數值。如果不能,在呼叫toString()方法,並測試其返回值。這個我也不太懂,我往後看看,再補充~~

1.4 數值轉換
終於到了這個地方,我們在開發中關於數值方面出的bug一般從此處出現。。。
有三個函式可以將非數值轉換為數值:Number(),parseInt()和parseFloat()。
Number()是轉型函式,可以用於任何資料型別。parseInt()和parseFloat()函式主要用於將字串轉換為數值。對於同樣的引數,這三個函式執行的操作也不同。
Number()函式基於如下規則執行轉換。

型別 轉換結果
Boolean true 1
Boolean false 0
Number Number 直接返回
Null null 0
Undefined undefined NaN
String 字串包含數字或者、包括數值字元前包含+/-號則轉換一個十進位制數值 返回或略前面0的數值
String 字串有效的浮點值格式,如1.1 返回同樣的1.1,(同樣有0忽略0)
String 字串包含有效的十六進位制格式 會返回轉換為十六進位制對應的十進位制數值
String 如果字串包含除上述情況之外的其他字元、 NaN

物件,呼叫valueOf()方法,並按照上述轉換返回值,如果返回NaN,則呼叫toString()方法,再按照轉換字串的規則轉換。

從不同資料型別到數值的轉換有時候比較複雜~,多看看上面的轉換規則。

考慮到用Number()函式轉換字串時相對負責且有點反常規,通常在需要得到整數的時候可以優先使用parseInt()函式。parseInt()函式更專注於字串是否包含數值。字串最前面的空格會被忽略,
如果第一個字元時 不是數值字元 或 +/-符號,會立即返回NaN。這意味這空字元也會返回NaN。
如果第一個字元是數值字元,+/-則繼續一次檢查每個字元直到字元末尾,或碰到非數值字元。如:”12哈哈哈“會被轉換為12,因為”哈哈哈“會被忽略,類似”12.5“也是會被轉換為12,因為小數點不是有效整數字符。

假設字串中第一個字元是數值字元,parseInt()函式也能識別不同的整數格式(十進位制,八進位制,十六進位制)。也就是字串以”0x“開頭,就會被解釋為十六進位制,如果字串以"0"開頭且緊跟數值(不好使~)在非嚴格模式下會被解釋為八進位制整數。

let num1 = parseInt("");	// NaN
let num2 = parseInt("0xA");	// 10,十六進位制
let num3 = parseInt(015);	// 13,八進位制
let num4 = parseInt("70");	// 70,十進位制

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

let num = parseInt("0xAF",16);	// 175

事實上,如果提供了十六進位制引數,那麼字串前面的"0x"可以省掉。

let num1 = parseInt("AF",16);	// 175
let num2 = parseInt("AF");	// 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,按十六進位制解析

建議,如果有型別轉換時,不可預測時,傳入底數進行控制。

parseFloat()函式的工作方式跟 parseInt()函式類似,都是從位置 0 開始檢測每個字元。同樣,
它也是解析到字串末尾或者解析到一個無效的浮點數值字元為止。這意味著第一次出現的小數點是有
效的,但第二次出現的小數點就無效了,此時字串的剩餘字元都會被忽略。因此,"22.34.5"將轉換
成 22.34。
parseFloat()函式與另一個不同之處在於,它始終忽略字串開頭的零。這個函式能識別前面討論的所有浮點格式,以及十進位制格式,parseFloat()函式只解析十進位制資料,也不能指定底數,十六進位制資料始終返回0。如果字串表示整數(沒有小數點或者小數點後面只有一個0),則parseFloat()返回整數。

let num1 = parseFloat("1234blue");	// 1234,按整數解析
let num2 = parseFloat("0xA");	// 0
let num3 = parseFloat("22.5");	// 22.5
let num4 = parseFloat("22.34.5");	// 22.34
let num5 = parseFloat("0908.5");	// 908.5
let num6 = parseFloat("3.125e7"); // 31250000
let num7 = parseFloat(0xA); // 10,這樣可以
let num7 = parseFloat(015); // 13, 這個也可以

公司換新領導,外包公司,兩個現場瘋狂切換最近沒有更新,我這麼菜還被人嫉妒~,救救我啊,不想管這麼多,這麼窮還內鬥啥,安心寫玩程式碼不好麼。