• 面向对象编程里面的继承


    上一节我简单写了创建对象的集中方法,关于对象,还有一个有趣的概念,那就是继承。

    OO语言,Object-Oriented,即面向对象编程。JS实现继承的方式叫做——实现继承,实现继承又是通过原型链来实现的。

      (#`皿´)   吼吼,听听这绕口令,就问你怕不怕!    (#`皿´)   

    一、原型链

    构造函数,原型和实例的关系,先默写吧。

     每个构造函数,都有一个原型对象。原型对象里包含一个指向构造函数的指针。而实例里包含一个指向原型函数的指针。他们之间的关系可以描述为:实例-->原型对象-->构造函数。

    现在,我们假设,某一个原型对象a其实是某个实例类型A。那么,原型对象a(实例A)-->原型对象a的构造函数B,同时也是实例A-->A的原型对象(构造函数B)-->A的构造函数C。这样,一条原型链就出来了。

    function SuperType(){
        this.property=true;
    }
    SuperType.prototype.getSuperValue=function(){
        return this.property;
    }
    function Sub(){
        this.sub='subValue';
    }
    Sub.prototype=new SuperType();//通过初始化继承了SuperType
    Sub.prototype.getSub=function(){
        return this.sub;
    }
    var instance=new Sub();
    console.log(instance.getSub());//subValue
    console.log(instance.getSuperValue());//true

     上面代码可以看到,通过继承,sub拥有了superType的属性和方法。而他的实现方法就是:创建一个SuperType的实例,然后将这个实例赋给sub的prototype属性中! 

    还有一个默认的链条。由于所有的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype.这也就是为什么所有的自定义类型都会继承toString()、valueOf()等默认方法的原因。

      

    二、确定原型和实例的关系

    第一种方法:采用instanceof操作符。只要用这个操作符测试实例与原型链中出现过的构造函数,结果就会返回true。

    console.log(instance instanceof Object);//true
    console.log(instance instanceof Sub);//true
    console.log(instance instanceof SuperType);//true

    第二种方法:isPrototypeOf()方法。注意,顺序反过来。这个方法是属于对象的prototype属性的。

    console.log(Object.prototype.isPrototypeOf(instance));//true
    console.log(Sub.prototype.isPrototypeOf(instance));//true
    console.log(SuperType.prototype.isPrototypeOf(instance));//true

    三、原型链存在的问题

    function Super(){
        this.colors=['red','blue','pink'];
    }
    function Sub(){
    }
    Sub.prototype=new Super();
    
    var obj1=new Sub();
    obj1.colors.push('black');
    console.log(obj1.colors);//["red", "blue", "pink", "black"]
    var obj2=new Sub();
    console.log(obj2.colors);//["red", "blue", "pink", "black"]

    看见没有,obj1把obj2给玷污了!

    包含应用类型值的原型属性会被所有实例共享!所以,这就是我们为什么要在构造函数中定义属性,而不是在原型对象中定义属性。

    在通过原型实现继承时,原型实际上会变成另一个类型的实例,于是,原先的是咧也就变成了现在的原型属性了。

    四、借用构造函数继承=伪造对象继承=经典继承

    为了弥补原型链继承的缺陷,就有了经典继承。基本思想是:在子类型构造函数的内部调用超类型构造函数。

    函数是在特定环境中执行代码的对象,通过使用apply()和call()方法,可以在新创建的对象上执行构造函数。 

    function Super(){
        this.colors=['red','blue','pink'];
    }
    function Sub(){
        //用call()方法继承Super
        Super.call(this);
    }
    var obj1=new Sub();
    obj1.colors.push('black');
    console.log(obj1.colors);//["red", "blue", "pink", "black"]
    var obj2=new Sub();
    console.log(obj2.colors);//['red','blue','pink']

     call()方法,“借调”了超类型构造函数。

    相对原型链来说,构造函数的优点是:可以在子类型构造函数中向超类型的构造函数传递参数。比如下面代码:

    function Super(name){
        this.name=name;
    }
    function Sub(){
        Super.call(this,'Alice');
        this.age=18;
    }
    var instance=new Sub();
    console.log(instance.name+instance.age);//Alice18

    五、组合继承=伪经典继承=原型链+构造函数

    组合继承,又叫伪经典继承,将原型链与构造函数组合到一起,实现的继承模式。

    function Super(name){
        this.name=name;
        this.color=['red','blue'];
    }
    Super.prototype.sayName=function(){
        console.log(this.name);
    }
    function Sub(name,age){
        Super.call(this,name);
        this.age=age;    
    }
    Sub.prototype=new Super();
    Sub.prototype.constructor=Sub;
    Sub.prototype.sayAge=function(){
        console.log(this.age);
    }
    var obj1=new Sub("Alice",18);
    obj1.color.push('black');
    console.log(obj1.color);//Array(3) ["red", "blue", "black"]
    obj1.sayAge();//18
    obj1.sayName();//Alice

    组合模式避免了两者的缺点,是js中最常用的继承模式。instanceofhe isPrototypeOf()能够识别基于组合继承创建的对象。

  • 相关阅读:
    前端提示“页面正在载入”的功能实现
    JSON那些事
    如何让nodejs同步操作
    nodejs的一些局限
    《javascript高级程序设计》读书笔记——作用域
    svn教程
    从雷军谈小米中的一些思考
    云Vps安全设置
    不同服务器数据库之间的数据操作
    C#语言的Excel文件导入导出
  • 原文地址:https://www.cnblogs.com/qingshanyici/p/10497766.html
Copyright © 2020-2023  润新知