JavaScript中的继承(上)


 在ES6之前,JavaScript中的继承是通过原型链来实现的;下面对此进行分析:

一、原型链

  首先需要明白构造函数、原型、实例之间的关系:
    1、每一个构造函数都有一个指向原型对象的prototype指针;
    2、原型对象有一个指向构造函数的constructor指针;
    3、每个实例都有一个指向原型对象的[[Prototype]]指针;
    
    原型链方法实现继承的基本思想就是:让原型对象等于另一个类型的实例,那么此时的原型对象包含着指向另一个原型的指针,以此类推,实现继承;

实现原型链的一种基本模式如下:
    function SuperType() {
        this.property = true;
    }
    SuperType.prototype.getSuperValue = function () {
        return this.property;
    };
    function SubType() {
        this.subproperty = false;
    }
    SubType.prototype = new SuperType();
    SubType.prototype.getSubValue = function () {
        return this.subproperty;
    };
    var instance = new SubType();
    console.log(instance.getSuperValue());//true
   以上代码,实现了SubType对SuperType的继承,这个例子中实例和原型的关系图如下:

    这种模式实现的继承也有其缺点:
    1、我们的原型会替换成另一个类型的实例,那么之前的实例属性变成了现在的原型属性,为最底层的所有实例共享;
    2、创建子类型的实例时,没有办法在不影响所有实例的情况下向超类型的构造函数传递参数;

    基于以上缺点,实际应用中很少单独使用原型链,为解决这一问题,开发人员又提出一种借用构造函数的技术

二、借用构造函数

   借用构造函数技术(又叫伪造对象或经典继承)的基本思想很简单:在子类型的构造函数内部调用超类型的构造函数。举例如下:
    function SuperType(name) {
        this.name = name;
        this.friends = ['Alice'];
    }
    function SubType() {
        SuperType.call(this, 'Jack');
        this.age = 29;
    }
    var instance1 = new SubType();
    var instance2 = new SubType();
    instance1.friends.push('Bob');
    console.log(instance1.name + ' ' + instance1.age);//Jack 29
    console.log(instance2.name + ' ' + instance2.age);//Jack 29
    console.log(instance1.friends);//["Alice", "Bob"]
    console.log(instance2.friends);//["Alice"]

    由以上代码可以看到:
    1、在创建SubType的实例时,在其构造函数内会调用SuperType的构造函数,结果是每个实例都保存着SuperType中属性的一个副本(通过操作friends属性可以得到验证);
    2、和原型链方式相比,借用构造函数的最大的优势是可以向父类传递参数(代码中的name参数);

   当然借用构造函数也有问题:函数都在构造函数中定义,那么每个实例都会有一个副本,无法实现函数复用。而且父类原型中的方法对子类不可见;
   
    考虑到构造函数技术的缺点,单独使用也很少见,更多优秀的继承方法请参考:JavaScript继承中篇

猜你喜欢

转载自blog.csdn.net/u013910340/article/details/70549565