iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 10
0

今天來介紹隱含的強制轉型。
隱含強制轉型,就是 JS 在一些運算上,自動幫你做轉型。
如果再不明白背後運作的原理,的確會用到滿肚子怒火。

隱含的強制轉型 (implicit coerion)

隱含地:String <--> Numbers

探討隱含轉型之前,先了解 + 做了什麼事。
ES5 section 11.6.1 的規格

var a = "42";
var b = "0";
a + b; // "420"

var c = 42;
var d = 0;
c + d; // 42

如果 + 兩側有任一個是 string,會串接兩側的 string。
如果 + 兩側都是 number,會計算兩側的值總和。

var e = [1,2];
var f = [3,4];
e + f; // "1,23,4" 

如果有一個 Object (含 array),會先呼叫 toPrimitive 來處理,後續就和 ToNumber 相同。所以 array 進行 valueOf() 拿不到基本型別就失敗,後續就用 toString() 方法變為 "1,2" 和 "3,4"。接著就是字串的串接了。

var a = {
    valueOf: function() { return 42; },
    toString: function() { return 4; }
}

a + "";      // "42"
String( a ); // "4"

a + "" 涉及了在 a 這個值上調用 valueOf() 的動作,回傳值會透過內部的 toString() 抽象運算被轉為一個 string。而 String(a) 只會直接調用 toString()。

+ 經過 toPrimive 運作方式,會先找 valueOf() 的動作,如果沒有的話,會再找 toString()。這樣就會回傳 42。
String() 會直接呼叫 toString 的方法,所以會回傳 4。

四則運算其他成員呢?
會將 String 轉成 Number,因為這些運算子只有運算的功能。

var a= "3.14"
a - 0; // 3.14
a * 1; // 3.14
a / 1; // 3.14

假設了解了物件在隱含強制轉型的原理,還是會有奇怪的範例。(之後會解釋)

[] + {}; // "[object Object]"
{} + []; // 0

綜合以上

+"1" +2 +[3] +{}
"1" "11" "12" "13" "1[object Object]"
2 "21" 4 "23" "2[object object]"
[3] "31" "32" "33" "3[object object]"
{} 1 2 3 "[object Object][object Object]"
  • array 和 object 因為沒有 toValue() 都會轉到 toString()。
  • 但是 {} 放在前面,會被當作是空的範圍,這時候只會對後面的值做 + toNumber 明確的強制轉型。
  • {} 放在後面,一樣會先找 valueOf(),但是是空陣列,後來還是找 toString()。也就是 "[object object]"。

除了 + 以外的四則運算?

var a = "3.14"
a - 0; // 3.14
a * 1; // 3.14
a / 1; // 3.14

+ 以外的四則運算子只被定義用於數值減法運算。也適用在 array 運算。

var a = [3];
var b = [1];
a - b; // 2

array 會先由 toString() 強制轉型為 string,再強制轉型為 number。

隱含地: Booleans --> Numbers

  • 與數字相加,Boolean 會轉成 Number。
var a = true;
a + 2; // 3

下面的功能,在於判斷 array 裡面的真值數量。

function onlyOne(){
    var sum = 0;
    for (var i=0; i < arguments.length; i++){
        if (arguments[i]){ // 若第 i 項為真值,就執行。
            sum += arguments[i]; // 隱性轉型的重點。
        }
    }
    return sum == 1; // 若總數為 1,回傳 true。
}

隱含地: * --> Boolean

哪些部分會隱含的轉換成 boolean

  1. if(..)
  2. for( ; .. ; ) 中間的。
  3. while(..) do.. while(..)
  4. 三元運算子 ? : ; 問號前面。
  5. || 和 && 左邊的運算元。

前四個是判斷式,需要判斷 Boolean 才能執行內部程式。

運算子 || 與 &&

都是先從左邊的運算元判斷。

a||b a = truthy a = falsy
b = truthy a b
b = falsy a b
a&&b a = truthy a = falsy
b = truthy b a
b = falsy b a

測試範例,一起來了解 JS 在背後做了哪些隱含強制轉型吧!

var a = 42;
var b = null;
var c = "foo";

if ( a && ( b || c )) {
    console.log("yep");
}

裡面做了幾件事。

  1. 先看小括號。
  2. b || c ,因為 b 是 false,回傳 c 的值 "foo"。
  3. a && "foo" ,因為 a 是 true,回傳 c 的值 "foo"。
  4. if("foo"),因為 "foo" 不是 falsy,回傳 true。
  5. 執行 console.log("yep")。

Symbol 的強制轉型

Symbol 轉 String

  • 明確的強制轉型 YES
  • 隱性的強制轉型 NO
var s1 = Symbol( "cool" );
String(s1); // "Symbol(cool)"
s1 + "";    // TypeError

下一章?

還沒,明天是第七章的最後部分。
會講相等性,寬鬆相等與嚴格相等。
主要是寬鬆的部分,裡面有用到隱含強制轉型。
最後有關係式的比較。

明天見!

參考資料

你所不知道的 JS


上一篇
Day9 - 明確的強制轉型
下一篇
Day11 - 寬鬆相等 VS. 嚴格相等
系列文
你為什麼不問問神奇 JavaScript 呢?30

尚未有邦友留言

立即登入留言