iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 9
0
自我挑戰組

你為什麼不問問神奇 JavaScript 呢?系列 第 9

Day9 - 明確的強制轉型

先談談明確的強制轉型,和一些看似明確,但只有知道才能當明確再用。
明不明確,是看程式碼的人的程度決定的事情。

明確的強制轉型

Explicit Coercion 指的是顯而易見且詳述的型別轉換。

(這裡面還有定義作者認為的顯而易見。)

明確地:String <--> Numbers

String() 和 Number() 是最明確的轉型。

var a = 42;
String(a);

var b = "3.14159";
Number(b);

+ 有點隱晦地明確。

a.toString();
+b;
  • 42.toString() 不能用在基本型別。
  • +b 要知道才會變明確。
  • -b 也能轉型,但會變負值。

但要小心 +b 的形式。

// 回想
42 .toFixed(2); // 用空格隔開

var c = "3.14";
var d = 5 + +c; // 請用空格隔開
d; // 8.14

日期轉數字

+也可以這樣用。

var timestamp = +new Date();
var timestamp = new Date().getTime();
var timestamp = Date.now(); // ES5

// polyfill
if (!Date.now) {
    Date.now = function() {
        return +new Date();
    };
}

建議不要使用與日期有關的強制轉型。

  • 取得現在時間: Date.now()
  • 取得特定時間: new Date(..).getTime()

~的奇幻旅程 ( the curious case of the ~ )

這段看書,搭配 MDN 效果更好。

~| 都是歸納在明確的轉型(書上有解釋。)

| 會將 Number 轉換成 ( 32位元 )。

var a = 3;
a|0; // 3 (0000 0000 0000 0000 0000 0000 0000 0011)
~a;
// -4 (1111 1111 1111 1111 1111 1111 1111 1111 1100)

因為第一個位元,用在判定正負號,所以上限值是
$$
0 + 2^{31} + 2^{30} + ... + 2^1 + 2^0 = 2147483647
$$

~ 的功用

~42; // -(x+1) --> -43
~-1; // 0

除了 -1 傳入值轉型後是 falthy 以外,都是 truthy。被稱為哨符值 (sentinel value)。用來幹嘛?
-1 代表失敗,其他的都是成功。用來做判斷式的內容。

.indexOf()

不存在的回傳值恰好是 -1。MDN 的解說。

var a = "Hello World";
if (a.indexOf("lo") >= 0) {/* 執行 */}; // true

if (a.indexOf("lo") < 0 ) { /* 不執行 */ }; // false

// 和
if (a.indexOf("ol") != -1) { /* 不執行 */ } // false

if (a.indexOf("ol") == -1) { /* 執行 */ } // true

// 等同於
if (~a.indexOf("lo")) {/* 執行 */}; // true
// ~a.indexOf("lo") === -4 --> truthy
if (!~a.indexOf("lo")) {/* 不執行 */}; // false
// ~a.indexOf("lo") === -4 --> truthy

截斷位元

除了用 Math.floor(..),還可以用 ~~。來截斷小數的部分。

但在負數的操作上,會有所不同。

Math.floor( 49.6 );  // 49
~~49.6;              // 49
Math.floor( -49.6 ); // -50
~~-49.6;             // -49
49.6|0;              // -49
-49.6|0;             // -49

floor 是向下約整,-50 比 -49 小。
優先使用 ~~ 不用 |0,是因為運算子的優先順序 (operator precedence)。

明確地:剖析數值字串

parseInt(..)

var a = "42px";
Number(a);   // NaN
parseInt(a); // 42

// ES5 以前的版本。現在測試結果會是 8、9。
parseInt(08);// 0
parseInt(09);// 0 
// 因為 08、09 在 JS 是八進制的表示法。

// 要注意是這樣使用,10 表示使用 十進制
// parseInt(string, 10)

剖析非字串

parseInt( 1/0, 19 ); // 18 what?!?!

因為 1/0 是 "Infinity"。在 19進制 下,I 代表 18。

不算是臭蟲,但要記得它的規則

parseInt(..) 強制將他的值轉為一個 string 以進行剖析動作。

其他範例

parseInt( 0.000008 );   // 0   (from "0.000008")
parseInt( 0.0000008 );  // 8   (from "8e-7")
parseInt( false, 16);   // 250 ("fa")
parseInt( parseInt, 16);// 15  ("f" from "function...")

parseInt( "0x10" );     // 16
parseInt( "103", 2 );   // 2   ("10")

明確地:* --> Boolean

  • 用 Boolean(a)
  • !!a
  • 盡可能別用 a? true : false

明確強制轉型總整理

  1. 除了使用 Native()。String()、Number()、Boolean()。
string number boolean
toString x a.toString() a.toString()
toNumber +a、(-a)、parseInt(a) parseInt(a,10) +a、(-a)
toBoolean !!a !!a x
  1. ~ 的用法。
    • 利用哨符值 -1。
    • 去除小數位。

參考資料

  1. 你所不知道的 JS
  2. ECMAScript® Language Specification
  3. MDN - indexOf()

上一篇
Day8 - 強制轉型
下一篇
Day10 - 隱含的強制轉型
系列文
你為什麼不問問神奇 JavaScript 呢?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言