iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 10
0
Modern Web

【這些年我似是非懂的 Javascript】系列 第 10

【這些年我似是非懂的 Javascript】Day 10 - 魔幻邪惡的強制轉型 #第三章 #隱含的強制轉型

今天要來聊聊這個主題的主角 隱含的強制轉型
如果還沒看過前兩篇的可以斟酌觀看~
以下連結奉上~
【這些年我似是非懂的 Javascript】Day 8 - 魔幻邪惡的強制轉型 #第一章 # 心情轉折
【這些年我似是非懂的 Javascript】Day 9 - 魔幻邪惡的強制轉型 #第二章 #明確的強制轉型

那我們就開始今天的內容~


因為恐懼所以你憤怒

圖片來源

假使說你用的是一個強型別的語言,並且想將x要從 A type 轉到 C type 並存到 y ,但是這中間必須先轉成 B type,如以下範例。

CType x = CType(BType(y));

假使說那個語言可以簡化定義使用方式可以用以下的方法實作

CType x = CType(y);

簡化了了先轉換 B Type 這個動作,增加可讀性但卻省略了中間隱藏了那些轉換的細節,你會那麼在乎這中間省略的步驟嗎?

我個人感覺會偏向可以省略成下面的方案,
對我來說如果知情就沒什麼好怕的了。

我們可以選用他好的一面,並且熟悉他去避開他可能會發生的事情,我覺得這滿重要的,一蓋的去否定反而減少了該語言好的特性。

這章節我們就來好好與它做朋友

隱含的 String 與 Number 的強制轉型

昨天講過明確的強轉型關於 String 和 Number ,
這邊也是同個主題但是主角是"隱含的"。
先來看一下以下範例

const a = '16';
const b = '1';

const c = 16;
const d = 1;

a+b // 161
c+d // 17

為什麼會有像是以上的結果?
簡單來說就是運算元的部分是否有一個或是兩個 String ,而這邊的 + 就會以為要是 String 的串接。

看過前幾篇的你一定知道我接著要說什麼...

上面說的部分是錯的哦!

如果上面說的是對的話那該如何解釋下面這個範例

const a = [1,2];
const b = [3,4];

a+b; // "1,23,4"

這明顯已經將兩個都不是 String,但是卻將兩邊轉成 String 並且串接起來了。

依據 ES5 語言規格的 section 11.6.1,如果有其中一個運算元是 String 或是接下來的任一步驟會產生 String 的值時用 + 就會進行 String 的串接,那 + 所用的演算法又剛好對應到剛剛用的 Array ,當 + 遇到一個 Object (包含 Array),作為任一運算元時,他會先呼叫 ToPrimitive 抽象運算來先處理該值,然後接著呼叫 [[DefaultValue]],並依照上下文情境傳入 number 來作為 hint 偏好型別。 (這邊的上下文情境其實我也不太懂 Orz)
接著又依據 ToNumber 的抽象運算處理 object ,當他沒辦法在 array 進行 valueOf() 產生簡單的基值,它就會改使用 toString() 表示法,導致他變成以下的結果

"1,2"+"3+4"; // 1,23,4

看不懂?

大致上來說就是
今天 + 看到他左右手其中一個是 Object 他會想先把他轉成 Number 然後 ToNumber 看不懂...就給了 toString() 處理。

書中提到在使用 JS 日常中最常看到的是以下範例

const a = 19;

const c = a+"";
c // "19"

他強制轉型成 String,因為剛剛提到的第一點是他先看兩邊運算元其中有一個 String 他就會判定要進行字串相加。

那如果想要轉回來怎麼辦?

與他對立的 - 出現了xD
直接看範例

const a = "19";

const c = a-0;
c // 19

- 這個運算子只被定義用來做數值的相減,
所以會迫使 a 強迫轉型成 Number。

*/ 也有相同效果

那如果將剛剛的範例再一次並且使用 - 呢?
器跨買~

const a = [1,2];
const b = [3,4];

a-b; // NaN

他們會先將 array 的值都會先被強制轉型成 String 然後在變成 number,最後才會進行 - 的動作。

也就是你把他再變成那再簡單一點

const a = [1];
const b = [2];

a-b; // -1

登愣~
結果就如你所願。

我個人也覺得非常有趣書中提到的一點是,儘管社群裡在怎麼被說邪惡啊魔幻,但相比 a = b +"" 的用法卻比 String(..) 這種明確的用法來的常見且實用 xDD

那我就問你!
你還憤怒嗎?
如果是那就是你還害怕 (開玩笑的)

隱含的 Boolean 與 Number 的強制轉

看書上說 (完全撇除責任xD)

強制轉型能發光發熱的地方在於將某個複雜的 boolean 邏輯簡化成簡單的數值加法運算。
(這不是通用技巧,只是單純看情況的專用解法)

來看看下面的範例的情境

function onlyOne(a,b,c){
    return !!((a && !b && !c) || (!a && b && !c) || (!a && !b && c) )
};

const a = true;
const b = false;

onlyOne(a,b,b); // true
onlyOne(b,a,b); // true
onlyOne(a,b,a); // false

簡單來說上面的範例想要做的是參數中只有一個為 true 或 truthy 就回傳 true,反之如果有兩個以上就是 false,那如果這個範例改成處理很多很多很多個值怎麼辦?

這時候就可以展現真正的技術了(誤

function onlyOne(){
    let sum = 0;
    for (let v of arguments){
        if (v) sum+= v;
    }
    return sum == 1;
};

const a = true;
const b = false;

onlyOne(a,b,b); // true
onlyOne(b,a,b); // true
onlyOne(b,b,b,a,b); // true

onlyOne(a,b,a); // false
onlyOne(a,a,b,a,b,b,b,a); // false

簡單來說就是讓隱含的強制轉型將所有的 Boolean 變成 0 或是 1 ,並且將所有的參數都相加,如果最終結果等於 1 回傳 true,否則回傳 false,完全符合剛剛的需求。

隱含的從任何非 Boolean 值強制轉型成 Boolean

什麼時候的運算式會需要隱含的強制轉型?
其實超常見的

  1. if(..)
  2. for(..)
  3. while(..)
  4. ?: (三元運算式)
  5. || 、 &&

以上那些就算不是 Boolean 也會被強制轉型成 Boolean。


今天是第十天,
剩餘完賽還有二十天~
今天早上睡過頭了黃金讀書時間破滅xDD
但後續還是照著原本的行程走~

以上為今天分享的內容
希望對你有幫助


感謝您的收看
我們明天繼續分享"魔幻邪惡的強制轉型系列最終章!"

我們明天見~


參考來源:

你所不知道的 JS|導讀,型別與文法 (You Don't Know JS: Up & Going)


上一篇
【這些年我似是非懂的 Javascript】Day 9 - 魔幻邪惡的強制轉型 #第二章 #明確的強制轉型
下一篇
【這些年我似是非懂的 Javascript】Day 11 - 魔幻邪惡的強制轉型 #最終章 #隱含的強制轉型
系列文
【這些年我似是非懂的 Javascript】34

尚未有邦友留言

立即登入留言