iT邦幫忙

2022 iThome 鐵人賽

0
Modern Web

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

Day62 Type 強制轉型:轉為 Number (數學運算 & 比特/位運算)

  • 分享至 

  • xImage
  •  

數學運算

-*/ 都是專屬於數學計算的運算子,因此會將運算元強制轉型為 number

首先來看看 - 號運算子,它與 + 號運算子的邏輯十分相似:

console.log(5 -"3.14");  // 1.8599999999999999
console.log(5- -"3.14"); // 8.14

console.log("3.14" - 0); // 3.14
console.log(- -"3.14");  // 3.14

5 -"3.14" 之所以會得到 1.8599999999999999,是因為某些小數無法用精確的二進表示,於是出現了誤差(要如何預防誤差,在 《Type 數字》這篇文章已做說明)。

- 運算子除了表示減法之外,也能夠表示數字的正負,所以 5- -"3.14"; 實際上是 5- (-3.14);,最後獲得 8.14 這個值,- -"3.14" 則是將 "3.14" 轉型為 number 以後翻轉了正負號兩次,和 - 0 擁有同樣的效果。

除了 string 以外,其他的型別遇到 - 也都被轉為 number

console.log(-true);      // -1
console.log(-null);      // -0
console.log(-undefined); // NaN
console.log(-[]);        // -0
console.log(-{});        // NaN
console.log(-function(){}); // NaN

接著來看看 */,這兩個運算子並沒有表達正負數的功能,所以需要兩個運算元組合應用:

console.log("3.14" * 1); // 3.14
console.log("3.14" / 1); // 3.14

console.log([3] * [2]);    // 6
console.log([] * 1);        // 0
console.log([1, 2, 3] * 1); // NaN
console.log({} * 1);        // NaN
console.log({ a: 1 } * 1);  // NaN

"3.14" 在數學運算中被強制轉型為 number,而 [3] * [2] 則是先執行了 ToPrimitive 轉換成 string 獲得 "3""2",再被轉為數字進行相乘。


比特/位運算

~ 運算子

~ 運算子(bitwise NOT operator)大多被譯為「比特非」、「按位取反」或「位元補數」,它的功能是進行二進制的補數,也就是 ~x 會變成 -(x+1)

~ 運算子首先會將值使用 ToInt32 強制轉型為一個 32 位的 number,然後執行按位取反,也就是翻轉每一個比特位。

console.log(~42.5678) // -43
console.log(~"-42")   // 41
console.log(~"abc")   // -1
console.log(~NaN)     // -1

按照 ~x 會變成 -(x+1) 這個邏輯,~x 唯一會得到 0 的數字則是 -1(或者說是 >= -1< 2 的任意數字 )。

-1 是一個常見的哨兵值(sentinel value),許多語言的部分方法中,當返回 >= 0 的值表示成功,返回 -1 則表示失敗。

比如說 JS 的 indexOf,便能夠利用 ~ 只有 -1 會返回 0 的特性來檢查是否成功:

var str = "Hello World";

function foo(x) {
  if (~str.indexOf(x))
    console.log("found it!")
  else
    console.log("not found!")
}

console.log(~str.indexOf("lo")); // -4,truthy value
console.log(~str.indexOf("ol")); // 0,falsy value

foo("lo"); // "found it!"
foo("ol"); // "not found!"

~~ 運算子

~~ 運算子(double NOT bitwise operator)如字面所示,是兩次的 ~ 運算,也就是 ~~x 會變成 -(-(x+1)+1) 。基於以上特性,~~ 也常被視為 Math.floor 的簡化寫法:

console.log(~42.5678) // -43
console.log(~~42.5678) // 42
console.log(Math.floor(42.5678)) // 42

console.log(~"42.5678") // -43
console.log(~~"42.5678") // 42
console.log(~~"abc") // 0

但要注意 ~~Math.floor 作用在負數的結果並不相同:

console.log(~-42.5678) // 41
console.log(~~-42.5678) // -42
console.log(Math.floor(-42.5678)) // -43

如果要將 ~~ 作為截斷小數的方法,記得永遠將它只用於正數上。

| 運算子

| 運算子,又稱「比特或」或者「案位或」(bitwise OR),它會將傳入的數進行 ToInt32 轉換,並將兩者進行「或」運算(比特位的任一值為 1 時返回 1)。

基於以上特性,| 運算子的第一個運算式為假值時,會返回第二個運算式的 ToInt32 結果:

console.log(0 | -0); // 0
console.log(0 | NaN); // 0
console.log(0 | Infinity); // 0
console.log(0 | -Infinity); // 0

console.log(0 | 42); // 42
console.log(0 | 42.1111); // 42
console.log(0 | -42); // -42
console.log(0 | -42.1111); // -42

console.log(0 | "-42"); // -42
console.log(0 | "-42.1111"); // -42
console.log(0 | "abc"); // 0

~~ 不同的是,0 | x 對負數的運算結果和 Math.floor 是相同的。


參考資料


上一篇
Day61 Type 強制轉型:+ 加號運算子
下一篇
Day63 Type 強制轉型:轉為 Boolean、Symbol 強制轉型
系列文
就是要搞懂 JavaScript 啦!73
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言