zoukankan      html  css  js  c++  java
  • JavaScript基础概念之----面向对象----继承(深入)

    实现继承主要是依靠原型链来实现的。

    基本思想是:利用原型 让一个引用类型继承另一个引用类型的属性和方法。

    原型链继承

    有两个构造函数 A 和 B,如果,让A的原型对象等于B的实例,结果会是怎么样呢?

    此时 A 的原型对象将包含一个指向 B 的原型的指针,相应地,B 的原型中也可包含着指向 C 的指针。假如 C 的原型又是 D 的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是原型链的基本概念。

    继承实现的本质,就是重写原型对象,代之以一个新类型的实例。

    function A(){
        //...
    }
    
    A.prototype.getA = function(){
        //...
    }
    
    function B(){
        //...
    }
    
    B.prototype = new A() //继承了A
    
    B.prototype.getB = function(){
        //...
    }
    
    var o = new B();
    console.log(o.getA()) //在B构造函数创建的对象o中,执行A构造函数的方法

    调用o.getA()会经历三搜索步骤:

    • 搜索实例o
    • 搜索B.prototype
    • 搜索A.prototype

    所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。

    instanceof 操作符 确认实例 是否 原型链中出现过的构造函数的实例

    o instanceof Object //true
    o instanceof A //true
    o instanceof B //true

    isPrototypeOf()方法

    Object.prototype.isPrototypeOf(o) //true
    A.prototype.isPrototypeOf(o) //true
    B.prototype.isPrototypeOf(o) //true

    给原型添加方法的代码,一定要放在替换原型的语句之后。

    function A(){}
    
    A.prototype.getA = function(){}
    
    function B(){}
    
    B.prototype = new A() //继承了A
    
    //新增的方法
    B.prototype.getB = function(){}
    
    //重写超类中的方法
    B.prototype.getA = function(){}
    
    var o = new B();
    console.log(o.getA())
    //重写的方法会屏蔽超类中的方法

    通过原型链实现继承时,不能使用对象字面量创建原型方法。因为这样会重写原型链。

    function A(){}
    
    A.prototype.getA = function(){}
    
    function B(){}
    
    B.prototype = new A() //继承了A
    
    B.prototype = {
      getB:function(){},
      getOther:function(){}
    }
    
    
    var o = new B();
    console.log(o.getA())  //报错

    缺点:

    • 原型的共享本性的原因,通过原型实现继承时,原型实际上会变成另一个类型的实例。原先的实例属性也就变成了现在的原型属性了。
    • 在创建子类型的实例时,不能向超类型的构造函数中传递参数

    构造函数继承

    基本思想是:在子类型构造函数的内部调用超类型构造函数。

    function A(){
        this.arr = [1,2,3]
    }
    
    function B(){
        A.call(this) //继承了A
    }
    
    var o1 = new B();
    o1.arr.push(3);
    console.log(o1.arr) //1,2,3,4
    
    var o2 = new B()
    console.log(o2.arr) //1,2,3

    可以在子类型构造函数中向超类型构造函数传递参数

    function A(name){
        this.name = name;
    }
    
    function B(){
        A.call(this,'adhehe') //继承了A,同时传递参数
        
        this.age = 23;
    }
    
    var o = new B();
    console.log(o.name) //adhehe
    console.log(o.age) //23

    缺点:

    • 方法都在构造函数中定义,函数复用无从谈起
    • 在超类型原型中定义的方法,对子类型是不可见的

    组合继承(原型链继承 与 构造函数继承 组合)

    基本思想是:使用原型链实现对原型属性和方法的继承,使用构造函数实现对实例属性的继承。

    组合继承避免了原型链和构造函数的缺陷,融合了它们的优点,是JavaScript中最常用的继承模式。并且,instanceof和isPrototypeOf()也能够用于识别基于组合继承创建的对象。

    function A(name){
        this.name = name;
        this.arr = [1,2,3];
    }
    
    A.prototype.getName = function(){}
    
    function B(name,age){
        A.call(this,name) //继承属性
        
        this.age = age;
    }
    
    //继承方法
    B.prototype = new A();
    B.ptototype.constructor = B;
    B.ptototype.getAge = function(){}
    
    var o1 = new B('adhehe',23);
    o1.arr.push(4)
    o1.arr //1,2,3,4
    o1.getName() //adhehe
    o1.getAge() //23
    
    var o2 = new B('Jhone',45);
    o2.arr //1,2,3
    o2.getName() //Jhone
    o2.getAge() //45

    缺点:无论在什么情况下,都会调用两次超类型构造函数。一次是创建子类型原型的时候,一次是在子类型构造函数内部。

    原型式继承

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

    这种原型式继承,要求必须有一个对象可以作为另一个对象的基础。

    function Object(o){
        function F(){}
        F.prototype = o;
        return new F();
    }
    var person = {
        name:'adhehe',
        colors:['red','blue','yellow']
    }
    
    var o1 = object(person);
    o1.name  = 'Greg';
    o1.colors.push('pink');
    
    var o2 = object(person);
    o2.name = 'Linda';
    o2.colors.push('gray');
    
    console.log(person.colors) //'red','blue','yellow','pink','gray'

    ECMAScript5新增Object.create()方法规范化了原型式继承

    var person = {
        name:'adhehe',
        colors:['red','blue','yellow']
    }
    
    var o1 = Object.create(person)
    o1.name  = 'Greg';
    o1.colors.push('pink');
    
    var o2 = Object.create(person);
    o2.name = 'Linda';
    o2.colors.push('gray');
    
    console.log(person.colors) //'red','blue','yellow','pink','gray'

    Object.create()方法的第二个参数 与 Object.defineProperties()方法的第二个参数格式相同:每个属性都是通过自己的描述符定义的。以这种方式指定的任何属性都会覆盖原型对象上的同名属性。、

    var person = {
        name:'adhehe',
        colors:['red','blue','yellow']
    }
    
    var o = Object.create(person,{
        name:{
            value:'Greg'
        }
    })
    
    console.log(o.name) //Greg

    寄生式继承

    与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再返回对象。

    function object(o){
        function F(){}
        F.prototype = o;
        return new F():
    }
    
    function createPreson(arg){
        var clone = object(arg);
        clone.sayHi = function(){}
        return clone;
    }
    
    var preson = {
        name:'adhehe',
        colors:['red','blue','yellow']
    }
    
    var o = createPerson(person);
    o.sayHi(); 

    任何能够返回新对象的函数都适用于此模式。

    寄生组合式继承

    通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

    基本思想是:不必为了指定子类型的原型而调用超类型的构造函数,我们需要的无非是超类型原型的一个副本而已。

    function person(sub,sup){
        var ptototype = object(sup.prototype); //创建对象
        prototype.constructor = sub; //增强对象
        sub.prototype = prototype;   //指定对象
    }
    //第一步,创建超类型原型的一个副本
    //第二步,为创建的副本添加constructor属性,弥补因重写原型而失去的默认的constructor属性
    //最后一步,将新创建的对象赋值给子类型的原型
    function Sup(name){
        this.name = name;
        this.colors = ['red','blue','yellow']
    }
    
    Sup.prototype.sayName = function(){}
    
    function Sub(name,age){
        Sup.call(this,name)
        this.age = age;
    }
    
    person(sub,sup);
    
    sub.prototype.sayAge = function(){}
  • 相关阅读:
    21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
    34. Find First and Last Position of Element in Sorted Array
    leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、301. Remove Invalid Parentheses
    31. Next Permutation
    17. Letter Combinations of a Phone Number
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    oc 异常处理
    oc 类型判断
    oc Delegate
    oc 协议
  • 原文地址:https://www.cnblogs.com/adhehe/p/9788964.html
Copyright © 2011-2022 走看看