理解js中原型链的封装继承多态

前言

面向对象有三大特性:封装继承多态。

不过,js和java的封装继承多态是不一样的,我和从事java开发的朋友有过一次对话(抬杠 !--)。

我说:javascript也是面向对象语言,

他说:不对吧,js不是面向对象吧。

我说:是的,官方说的就是面向对象语言。

他说:那你知道三大特性吗?

我说:封装继承多态。

然后他说:那你说一下那都是啥意思。

我说:构造函数...原型对象...原型链....

他说:你说的这都是啥呀,构造函数和原型链是啥,听都没听过,面向对象使用类,你那js是假的面向对象吧。

我说:js后面用的是类,但在类之前用的是原型链。其实,类也是原型链的语法糖,不归根到底还是原型链吗。

因为我不懂java,他不懂js。不过js确实和java在面向对象的实现上是不一致的,js在class出来之前,是通过原型链的特性实现了面向对象编程。

家有儿女

今天这篇文章,我用《家有儿女》来通俗的说一下js中原型链是怎么完成封装继承多态的,class相关的这篇文章不提。

构造函数构建家庭成员

        function Family(name, gender, token) {
            //姓名
            this.name = name
            //性别
            this.gender = gender
            //身份
            this.token = token
            //家里有好多本书
            this.bookList = ['资治通鉴', '百家菜谱', '七龙珠', '三体']
            //家里的厨房可以用来做饭
            this.useChuFang = function (type, name) {
                console.log(`我用${type}做出了我想吃的${name}`)
            }
            //使用电脑
            this.computer = function (type) {
                //电脑有显卡,键盘,内存条,处理器等
                let xianka = () => { }
                let jianpan = () => { }
                let chuliqi = () => { }
                let write = () => {
                    console.log(`我是${this.name},我会用电脑写小说`)
                }
                let playGame = () => {
                    console.log(`我是${this.name},我会用电脑打游戏`)
                }
                switch (type) {
                    case "write":
                        write()
                        break
                    case "playGame":
                        playGame()
                        break
                    default:
                        console.log(`我是${this.name}抱歉,我不懂电脑的构造和具体原理`)
                }
            }
            //使用化妆品
            this.useHuaZhuangPin = function(){
                if (this.gender === 'woman') {
                    console.log(this.name,'你是女性,可以使用这些化妆品')
                } else {
                    console.log(this.name,'男人就别作妖了')
                }
            }
            //私有变量,10瓶饮料
            drinks = 10
            //闭包返回函数
            let fn = (num,name, drinks) => {
                if(drinks>-1){
                    console.log(`我是${name},我拿了${num}瓶饮料,还剩${drinks}瓶饮料`)
                }else{
                    console.log(`我是${name},我想拿饮料,发现没了`)
                }
                
            }
            //闭包封装私有变量,家里的饮料
            this.drinkFun = (num,name) => {
                drinks = drinks - num
                return fn(num,name, drinks)
            }
                        //家庭有一笔1百万的存折
                         bankBook = 1000000
        }



        let XiaDongHai = new Family('夏东海', 'man', '父亲')
        let XiaoXue = new Family('小雪', 'woman', '女儿')
        let LiuMei = new Family('刘梅', 'woman', '母亲')
        let LiuXing = new Family('流星', 'man', '儿子')
        console.log(XiaDongHai, '夏东海')
        console.log(XiaoXue, '小雪')
        console.log(LiuMei, '刘梅')
        console.log(LiuXing, '流星')
测试

理解js中原型链的封装继承多态_第1张图片

结论:

一个构造函数就像是一个家庭,这个家庭有一些资产,是大家所共有的,每个家庭成员都可以去使用和调配这些资产,每个家庭成员都有原型链定义的方法属性和自己独有的属性。

封装

        //1.构造函数封装公共方法
        //夏东海用电脑写文章
        XiaDongHai.computer('write')
        //流星用电脑打游戏
        LiuXing.computer('playGame')
        //你问他们电脑的显卡原理是什么
        XiaDongHai.computer('xiaka')
        //他们虽然不懂电脑是怎么运行的,但是他们可以用电脑做到自己想做的事。

        //2.闭包封装私有变量
        //全家喝饮料
        XiaDongHai.drinkFun(3,'夏东海')
        LiuMei.drinkFun(2,'刘梅')
        LiuXing.drinkFun(4,'流星')
        XiaoXue.drinkFun(1,'小雪')
        XiaDongHai.drinkFun(1,'夏东海')
测试

理解js中原型链的封装继承多态_第2张图片

 结论

构造函数内部可以封装公共属性方法,闭包可以封装私有变量,都可以让所有的实例对象去操作这些属性方法,并且无需知道这些属性方法是内部是如何构造的。

公共资产只要你是这个家庭成员,你就可以用它。你可以不用知道这个东西的构造原理是什么,你只需要会使用它。

你不需要会包饺子,你只需要会吃饺子

继承

        
        //给构造函数,也就是全家添加100万元的家庭资产和一辆奔驰轿车
        Family.prototype.bankBook = 1000000
        Family.prototype.car = '奔驰'

        //接下来我就用代码来清晰的展示面向对象的这些特征
        //构建家庭成员,其实构造函数的本质作用,就是用来批量创建一些拥有相同属性或者方法的对象,不让代 
        码大量冗余重复。
        let XiaDongHai = new Family('夏东海', 'man', '父亲')
        let XiaoXue = new Family('小雪', 'woman', '女儿')
        let LiuMei = new Family('刘梅', 'woman', '母亲')
        let LiuXing = new Family('流星', 'man', '儿子')

理解js中原型链的封装继承多态_第3张图片

 测试
      
        //夏东海将原来的奔驰车卖掉了,换了一辆新宝马车,花了10万元
        Family.prototype.car = '宝马'
        console.log(Family.prototype.bankBook,'???')
        Family.prototype.bankBook = Family.prototype.bankBook - 100000
  
        console.log(XiaDongHai.car,XiaDongHai.bankBook,'夏东海')
        console.log(LiuMei.car,LiuMei.bankBook,'刘梅')

 

 结论

  原型链可以添加,重写一些公共属性,所有实例对象继承原型对象的属性都会受到影响。

  夏东海花了家里的公共财产,所有家庭成员拥有的共同财产就会减少。但是买了新车,以后所有成员就都能坐上宝马新车了。

同甘共苦

多态

        //夏东海和刘梅做饭
        LiuMei.useChuFang('鸡块','大盘鸡')
        XiaDongHai.useChuFang('方便面','泡面')
        //流星和小雪化妆
        LiuXing.useHuaZhuangPin()
        XiaoXue.useHuaZhuangPin()
测试

理解js中原型链的封装继承多态_第4张图片

结论

不同的方法被不同的对象调用,结果会多样性。

龙生九子各不同

结束语

其实我说的也不是很详尽,只是想变着法的想让看客明白原型链的具体作用和实际运用方法,熟练理解原型链是js开发者最重要的技能之一,现在你可以想一下vue是不是也是使用原型链的特性去让各组件操作原型上的实例方法呢。

更多继承方法请看:

js中继承的方法-CSDN博客

感觉有用的给个赞吧!

你可能感兴趣的:(js,javascript)