JavaScript学习笔记6 面向对象之继承

  • 原型链
    • 别忘记默认原型
    • 确定原型和实例的关系
    • 谨慎的定义方法
    • 不能使用字面量添加新方法
    • 原型链的问题
  • 借用构造函数
    • 传递参数
    • 借用构造函数的问题
  • 组合继承
  • 原型式继承
  • 寄生式继承
  • 寄生组合式继承

原型链


    /**
     *              继承
     * 许多OO语音都支持两种继承方式: 接口继承和实现继承
     * 1.接口继承: 只继承方法签名  不继承实现
     * 2.实现继承:继承实际的方法
     * 
     * 如前所述,由于函数没有签名,在ECMAScript中无法实现接口继承。
     * ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的。
     * 
     */



    /**
     *              原型链
     * 原型链作为实现继承的主要方法,基本思想是:利用原型让 引用类型A 继承引用类型B 的属性方法。
     * 简单回顾构造函数、 原型和实例的关系:
     * 1.每个构造函数都有一个原型对象
     * 2.原型对象都包含一个指向构造函数的指针
     * 3.实例都包含一个指向原型对象的内部指针
     * A构造函数  A原型对象    A实例
     * B构造函数  B原型对象    B实例
     * 
     * 让A原型对象等于B类型的实例
     * A原型对象将包含一个指向B原型的指针
     * B原型对象中也包含着一个指B构造函数的的指针
     * 
     * 
     * 
     * 
     */

    function SuperType(){
        this.superProperty=true;
    }


    SuperType.prototype.getSuperValue=function(){
        return this.superProperty;
    };

    function SubType(){
        this.subproperty=false;

    }
    //让A原型对象等于B类型的实例
    //继承了SuperType
    SubType.prototype=new SuperType();

    SubType.prototype.getSubValue=function(){
        return this.subproperty;
    };
    var instance=new SubType();
    console.log(instance.getSuperValue())
    console.log(instance.getSubValue())

    /*
     * 上面的代码定义了SuperType 和SubType。 SubType继承了SuperType
     * 而继承是通过创建SuperType的实例,赋值给SubType.prototype实现的
     * 实现的本质是: 用一个新类型的实例去重写原型对象(原来纯在与SUperType的实例中的所有属性和方法,
     * 现在也存在与SubType.prototype 中)
     * 确定继承关系后又添加了getSubValue 这个方法。
     * 
     * 上面代码中 SubType 没有使用默认原型,而是换了一个新原型(SuperType实例),
     * 新原型有SuperType实例的属性和方法  还有一个指向SuperType原型的指针
     * 
     * 最终结果
         * 
         * 1.instance 指向SubType原型对象
         * 2.SubType原型对象指向SuperType 原型对象
         * 3.getSuperValue()方法仍在SuperType原型对象中(因为是原型方法)
         * 4.proterty在SubType.prototype中(因为是实例属性@see 5)
         * 5.SubType.prototype是SuperType的实例
         * 6.instance.constructor指向SuperType(constructor被重写)
         */

这里写图片描述

 /**
          * 通过实现原型链,本质上扩展了前面介绍的原型搜索机制。
          * 
          * 原型搜索机制:当以读取模式访问一个实例属性时,首先会
          * 在实例中搜索该属性。如果没有找到该属性,则继续搜索
          * 实例的原型。 
          * 
          * 在通过原型链实现继承的情况下,搜索过程就得以沿着原型链
          * 继续向上。例如:instance.getSuperValue()会经历三个
          * 搜索步骤
          * 1:搜索实例
          * 2:搜索SubType.prototype;
          * 3:搜索SuperType.prototype
          * 在找不到属性或方法时,会一直向上搜索,直到原型链末端才会
          * 停下 。
          * 
          */

别忘记默认原型

这里写图片描述

确定原型和实例的关系

这里写图片描述

谨慎的定义方法

//必须先用SuperType实例 替换SubType原型后 再定义方法(应为SubType原型被替换,将会找不到替换之前的方法)

/**
         * 谨慎的定义方法
         * 子类型有时需要重写父类型中的某个方法,或者添加父类型中没有
         * 的方法。但是给原型添加方法的代码一定要放在替换原型的语句之后
         */

        function SuperType() {
            this.property = true;
        }
        SuperType.prototype.getSuperValue = function() {
            return this.property;
        }

        function SubType() {
            this.subproperty = false;

        }
        //继承了SuperType  
        SubType.prototype = new SuperType();

        //必须先用SuperType实例 替换SubType原型后 再定义方法
        SubType.prototype.getSubValue = function() {
            return this.subproperty;
        };

        SubType.prototype.getSuperValue = function() {
            return false;
        }
        var instance =new SubType();
        console.log(instance.getSuperValue());//false

不能使用字面量添加新方法

在通过原型链实现继承时,不能使用对象字面量创建原型方法(因为会重写原型链,)
这里写图片描述

原型链的问题

1.父类型的实例属性,变成子类型的原型属性
/**
         * 1.父类型的实例属性,变成子类型的原型属性
         */

        function  SuperType(){
            this.colors=['red','blue','green'];
        }
        function SubType(){
        }
        //继承SuperType
        SubType.prototype=new SuperType();

        var instance1=new SubType();
        instance1.colors.push('black');
        console.log(instance1.colors);//'red,blue,green,black'
        var instance2=new SubType();
        console.log(instance2.colors);//'red,blue,green,black'

这里写图片描述

2.创建子类型时 ,没有办法在不影响所有对象实例的情况下,向父类型构造函数传递参数。

由于这两个问题,实践中很少会单独使用原型链

借用构造函数

借用构造函数:子类型构造函数的内部,调用父类型构造函数。
函数只过不是在特定环境中执行代码的对象,因此通过使用apply()和call()
方法可以在(未来将要)新创建的对象上执行构造函数(代码)
apply() 和call()详见 https://blog.csdn.net/csdn1125550225/article/details/80067801
作用域的问题详见 https://blog.csdn.net/csdn1125550225/article/details/80139005

    function SuperType(){
            this.colors=['red','blue','green'];
        }

        function SubType(){
            /**
             * 继承SuperType。 
             * 原理 :在SubType函数的作用域调用call(),设置SubType函数体内this
             * 对象的值(在SubType对象上执行SuperType()函数的所有对象初始化代码)。
             * 使SubType每个实例都拥有colors。
             */
            SuperType.call(this)//(相当执行了,this.colors=['red','blue','green'];)
        }
        var instance1=new SubType();
        instance1.colors.push('black');
        console.log(instance1.colors)//"red,blue,green,black"
        var instance2=new SubType();
        console.log(instance2.colors)//"red,blue,green"

SubType的每个实例都拥有了自己的colors

传递参数

/**
         * 传递参数:可以在子类型构造函数中向父类型构造函数传递参数
         */

        function SuperType(name) {
            this.name = name;
        }

        function SubType() {
            //继承了SuperType,同时传递了参数
            SuperType.call(this,'Nicholas');
            //实例属性 为了确保SuperType构造函数不会重写子类的属性,可以在调用父类之后在定义属性
            this.age=29;
        }
        var instance=new SubType();
        console.log(instance.name);//Nicholas
        console.log(instance.age);//29

借用构造函数的问题

借用构造函数的问题:属性和方法的复用问题,
方法都在构造函数中定义,原型中没有公共的属性和方法。
在父类型的原型中定义的方法,对子类型是不可见的,除非父类型的构造函数中定义,
但这样所有的类型都只能使用构造函数。所以 借用构造函数也是很少单独使用

组合继承

组合继承:将原型链借用构造函数组合到一块,发挥各自的长处的一种继承模式。
思路:使用原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。
好处:通过在原型上定义方法实现函数复用,又保证每个实例都有自己的属性

function SuperType(name){
            //定义了两个属性
            this.name=name;
            this.colors=['red','blue','green'];
        }
        //给SuperType原型定义方法
        SuperType.prototype.sayName=function  () {
            console.log(this.name)  
        }

        function SubType (name,age) {
            //借用构造函数  继承属性  
            SuperType.call(this,name);
            //定义自己的属性
            this.age=age;
        }
        //SubType通过原型链继承SuperType的方法
        SubType.prototype=new SuperType();
        //在新的原型上定义方法
        SubType.prototype.sayAge=function () {
            console.log(this.age)
        }

        var instance1=new SubType('Nicholas',29);
        instance1.colors.push('black');
        console.log(instance1.colors)//"red,blue,green,black"
        instance1.sayName()//"Nicholas"
        instance1.sayAge();//29

        var instance2=new SubType('Greg',27);
        console.log(instance2.colors)//"red,blue,green"
        instance2.sayName()//"Greg"
        instance2.sayAge();//27

总结
这里写图片描述

原型式继承

原型式继承:借助原型可以基于已有的对象创建新对象, 同时不必因此创建自定义类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值