【这些年我似是非懂的 Javascript】那些年我睡掉的物件导向 #浅谈 #Part 3

嗨各位~
今天要来分享一下关於上次提到 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
另外有自身英文进步的方式或撇步可以跟我分享,
我目前的想法是
美剧看爆!

感谢您我们下次见


<<:  Week38 - 各种安全性演算法的应用 - 概念篇 [高智能方程序系列]

>>:  日记19

轻松小单元 - 偶尔的急件,大陆厂牌产品禁用

这下还能不能到对面去发展呀(误 约莫去年底、今年初,正当大家都在与资安法交战时, 突然上头发布”禁用...

Day 13 AWS云端实作起手式第三弹 开始拼拼图吧

今天接着来看看如何搞定架设的设定档吧! 步骤 7 建立网站 在先前开启EC2时,我们透过user d...

第 10 天 别说吕布了,你听过青铜五小强吗 |Template-driven-form、ngModel、Template variables

前情提要 昨日我们聊了一些关於「页面」与「元件」在规划上,可能需要注意的地方。今天,我们会实际带着「...

[Day23] Tableau 轻松学 - TabPy 安装与连线

前言 对 TabPy 有一定程度的认识之後,便能开始学习 TabPy 安装与使用,这篇文章会分享如何...

Day 12 - Key Sequence Detection (KONAMI CODE)

前言 JS 30 是由加拿大的全端工程师 Wes Bos 免费提供的 JavaScript 简单应用...