iT邦幫忙

第 12 屆 iThome 鐵人賽

3
Modern Web

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

【這些年我似是非懂的 Javascript】那些年我睡掉的物件導向 #淺談 #Part 3

  • 分享至 

  • xImage
  •  

嗨各位~
今天要來分享一下關於上次提到 Javascript 沒有類別可以實體化只有物件,
那他到底缺乏甚麼?
答案是他不會複製物件到其他物件中,只會被連結在一起。
而這個類別複製行為就叫做 mixins 並且分為兩種:

  • 明確的
  • 隱含的

明確的 Mixins

因為 JS 不會自動複製,
所以我們可以自己做一個複製的行為,也有人稱他為 extend
如果以 CarVehicle 來舉例大概會長以下這樣

function mixin(sourceObj, targetObj){
    for(const key in sourceObj){
        // 沒有存在該 key 時再複製
        if(!(key in targetObj) targetObj[key] = sourceObj[key])
    }
}


const Vehicele = {
    engined = true,
    ignition: function(){
        console.log("Turning on the engine.");
    },
    drive: function(){
        this.ignittion();
        console.log("Steering and moving forward")
    },
}


const Car = mixin(Vehicele, {
    wheels: 4,
    drive: function(){
        Vehicle.drive.call(this);
        console.log(`Rolling on all ${this.wheels} wheels~`);
    };
});

依照上面來看 Car 有了 Vehicel 的特性和函式,實際上函式並沒有確實被拷貝而是單純參考,所以實際上只是複製了 ignition() 的一份參考的拷貝和 engined 的一個特性。(Drive 沒有被複製是因為原本 Car 就有了注意上面範例中的 if)

所以這部分你以為是你想的那樣嗎? xDD

Javascript: 想不到吧!?

重訪多型

剛剛在上面範例看到的 Vehicle.drive.call(this) 就是所謂的明確的虛擬多型,至於為何不直接用 Vehicle.drive() 那他就會被 this 綁定變成式呼叫 Vehicle 而不是 Car ,所以要確保Drive() 在 Car 中被呼叫就要使用 .call(this)
書中提到

因為 JS 這種特殊性,明確的虛擬多型會需要這種虛擬多型參考的每個函式中建立出脆弱的手動明確連結,導致會造成大量的成本產生雖然說他的確可以達到我們要的效果不過成本大於優點,所以不建議使用。

混合複製 (Mixing copies)

還記得剛剛那段 mixin 的程式碼嗎?

function mixin(sourceObj, targetObj){
    for(const key in sourceObj){
        // 沒有存在該 key 時再複製
        if(!(key in targetObj) targetObj[key] = sourceObj[key])
    }
}

這邊我們需要在迭代過程中檢查一下他有沒有相同名的特性再決定要不要複製,
那有沒有方式可以不要這樣?
答案是有的,
我們先指定 Car 特定的內容之前我們先做拷貝這樣我們就可以省略那一個判斷的步驟了!

來看看實際這樣做的結果吧

function mixin(sourceObj, targetObj){
    for(const key in sourceObj){
        targetObj[key] = sourceObj[key])
    }
}

const Car = mixin(Vehicel,{});
mixin({
    wheels: 4,
    drive: function(){
      // ...
    }
}, Car)

痾... 這樣看起來是不是造成了看起來更沒效率因為你要再次把東西又再次迭代進去xDD
所以正常不會選這種方式。

但是不管哪種方式其實都可以做到我們要的目的。

那到底的痛點還是一個就是...
Javascript 的函式沒辦法真正的被複製(目前沒有標準和可靠的方式),
所以阿...
當你修改了其中一個共用的函式物件像是增加一個特性或是做修改
那...

小結論

明確的 mixins 在 JS 中其實是不錯的機制,他可以解決很多個物件混進目標物件中,達成多重繼承的行為,但是實際上他不僅會造成一些隱含的危險比方說函式共用,還有可讀性的問題。

如果你覺得痛苦,那你就應該停止使用因為她所帶給你的利益已經遠遠不及造成的傷害。

James Harden 曾經說過...

就是告訴我們不要假會甚麼都不要用就好了!
複製貼上讓你的程式碼變成義大利麵再交給別人維護,
想要不維護別人的 legacy code 就要努力創造難以維護的 code 給別人維護。

(以上幹話可以不用看xD)

隱含的 Mixins

讓我們先來直接看範例

const ObjA = {
    foo: function(){
        this.bar = "Hey guys";
        this.boo = this.boo? this.boo + 1: 1;
    }
}

ObjA.foo();
ObjA.bar; // "Hey guys"
ObjA.boo; // 1

const ObjB={
    foo: function(){
        // ObjA 和 ObjB 有隱含的 mixins
        ObjA.foo.call(this);
    }
}

ObjB.cool();
ObjB.bar; // "Hey guys"
ObjB.boo; // 1 (不是 2 與 ObjA 共有

從上面可以看到藉由

ObjA.foo.call(this);

借用了 ObjA.foo() 並且在 ObjB 的環境中呼叫他並且結果是套用在 ObjB 物件上而不是原本的物件。

他實際上其實也是一個滿母湯的作法,
並且如果以可讀性來說就已經是要避免的寫法。

感謝您的收看
今天文章到此結束


題外話

今天一早去考多益去測試我自己菜英文的實力,果真是猜猜樂呢 xD
我朋友和女友都說

: 很浪費錢欸,你也沒什麼準備

但是對我來說其實這不是浪費錢,先墊墊自己實力再訂定目標去進步是不是一種策略?
比起這不敢那不敢,先不要這不要的
不如直接行動讓現實打臉你,你才知道妳自己有多麼不足需要去補 xD

如果我考很爛然後努力向上之後有大幅進步之後再來分享xD
另外有自身英文進步的方式或撇步可以跟我分享,
我目前的想法是
美劇看爆!

感謝您我們下次見


上一篇
【這些年我似是非懂的 Javascript】那些年我睡掉的物件導向 #淺談 #Part 2
下一篇
【這些年我似是非懂的 Javascript】Prototype #建構器
系列文
【這些年我似是非懂的 Javascript】34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言