- 、* 和 / 都是專屬於數學計算的運算子,因此會將運算元強制轉型為 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 是相同的。