iT邦幫忙

2022 iThome 鐵人賽

0
Modern Web

就是要搞懂 JavaScript 啦!系列 第 53

Day53 Type 特殊數字

  • 分享至 

  • xImage
  •  

接著來看看那些特殊的數字。

NaN

如果使用了並非 number 的值進行算術操作,操作失敗的結果則會產生一個不合法的 number,也就是 NaN。它在字面上代表一個「不是 numebrnumber(Not a Number)」,更準確來說,它實際上是一個「失敗」或「壞掉」的數字。

NaN 代表 number 集合內的一種特殊錯誤情況,也就是「進行數學操作後失敗的 numebr 結果」,因此 NaN 在型別上來說被歸類於 number

var a = 2 / "foo";
console.log(a); // NaN
console.log(typeof a === "number");	// true

NaN 也永遠不會等於任何值,包括它自己:

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

ES6 以前,可以用 isNaN 檢測 NaN,但它就如字面所示,檢查一個值「是否不是數字」,並且會試圖將傳入的值轉為數字來檢測:

console.log(isNaN(NaN)); // true
console.log(isNaN("B")); // true
console.log(isNaN(true)); // false,true 被強制轉型視為數字 1

ES6 以後新增了 Number.isNaN 方法,終於夠精準單一的檢測 NaN

console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("B")); // false
console.log(Number.isNaN(true)); // false

ES6 以前的填補如下(檢測不等於自己的值):

if (!Number.isNaN) {
	Number.isNaN = function(n) {
		return n !== n;
	};
}

無窮(Infinities)

JS 中明確定義了「無窮(Infinities)」:

console.log(1 / 0);  // Infinity

1 除以 0 的結果得到 Infinity,也就是 Number.POSITIVE_INFINITY;同樣地也對應存在 -InfinityNumber.NEGATIVE_INFINITY

var a = 1 / 0;
console.log(a);  // Infinity
console.log(a === Infinity);  // true
console.log(a === Number.POSITIVE_INFINITY);  // true

var b = -1 / 0;
console.log(b);  // -Infinity
console.log(b === -Infinity);  // true
console.log(b === Number.NEGATIVE_INFINITY);  // true

先前提到過 JS 使用 IEEE 754 運算標準,也就是說數字的表示形式是有限的,在進行加法或減法等操作時可能溢出可表現的最大/最小值,這種情況下就會得到 Infinity-Infinity

var a = Number.MAX_VALUE;
console.log(a);  // 1.7976931348623157e+308
console.log(a + a);  // Infinity
console.log(a + Math.pow(2, 970));  // Infinity
console.log(a + Math.pow(2, 969));  // 1.7976931348623157e+308

IEEE 754 遵循「就近捨入」模式,粗略意義上,Number.MAX_VALUE + Math.pow( 2, 969 ) 更接近 Number.MAX_VALUE,所以執行「向下捨入」,而Number.MAX_VALUE + Math.pow( 2, 970 ) 距离 Infinity 更更近,所以執行「向上捨入」。

數字一旦溢出無限值,就無法再回到正常數字,也就是有限能夠變成無限,但無限沒法回到有限。

至於「無限除以無限」等於多少?JS 的回答是 NaN

console.log(Infinity / Infinity); //NaN

至於一個有限的數字無以無限呢?等於 0

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

關於 -0 的話題,在下面繼續延伸。


JS 一個可能讓人困惑的地方,是它擁有普通的 0(正零),同時也擁有一個 -0(負零)。

為什麼會需要一個負零呢?在實際情境中,數字的大小表達了「量」,比方說遠近、高低、快慢、輕重;而正負號則表達了「方向」,也就是數字的值是往哪個方向移動的。

舉例來說,如果正數表示正向的座標,而負數表示負向座標,當座標位置歸零時,顯示 0 表示當前值是從正值而來的,-0 則表示是由負值變化為當前狀態,正負記號保存了關於「方向」的訊息。

在 JS 中,負零可以直接使用字面量定義,也可以從數字操作中得出:

console.log(0 * -3); // -0
console.log(0 / -3); // -0

有些版本的瀏覽器並不支持負零,而是依然以 0 顯示。

將一個負零由 number 轉換為 string 時,它會顯示為 0

var a = 0 / -3;
console.log(a); // -0

console.log(a.toString());  // "0"
console.log(a + "");  // "0"
console.log(String(a));  // "0"
console.log(JSON.stringify(a));  // "0"

然而反向的操作,也就是將字串 "-0" 轉為數字 -0 則是有效的:

console.log(+"-0"); // -0
console.log(Number("-0")); // -0
console.log(JSON.parse("-0")); // -0

如果對 0-0 進行比較,它們基本上難以區別:

var a = 0;
var b = 0 / -3;

console.log(a == b);  // true
console.log(-0 == 0); // true

console.log(a === b); // true
console.log(-0 === 0); // true

console.log(0 > -0);  // false
console.log(a > b);  // false

因此必須倚靠一些特殊方法來判斷:

function isNegZero(n) {
  n = Number(n);
  return (n === 0) && (1 / n === -Infinity);
}

console.log(isNegZero(-0));  // true
console.log(isNegZero(0 / -3));  // true
console.log(isNegZero(0));   // false

參考資料


上一篇
Day52 Type 數字
下一篇
Day54 Type 陣列
系列文
就是要搞懂 JavaScript 啦!73
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言