再看js继承

最近在复习JS知识,看到继承的时候,回去翻了一下《高级JavaScript程序设计》,顺便整理了一下书中的知识点,方便自己理解。

  • 基于原型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function Parent() {
    this.name = 'tom';
    }

    Parent.prototype.sayName = function() {
    return this.name;
    }

    function Child() {
    this.name = 'jack';
    }

    Child.prototype = new Parent();

    var child = new Child();

    child.sayName() // jack
    • 父类里面的引用类型的属性会被子类的实例修改,影响到其他子类实例
    • 子类实例化的时候无法向父类传递参数
  • 基于构造函数

    1
    2
    3
    function Child() {
    Parent.call(this)
    }
    • 父类原型被丢失
  • 组合继承

    1
    2
    3
    4
    5
    6
    function Child() {
    // 继承属性
    Parent.call(this)
    }

    Child.prototype = new Parent(); // 继承方法
    • 会调用两次父类构造函数
  • 原型式继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function object(o){
    function F(){}
    F.prototype = o;
    return new F();
    }

    var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
    };

    var anotherPerson = object(person);
    • 可以理解为 Object.create()
    • 借助原型可以基于已有的对象创建新对象。
    • 从本质上讲,object()对传入其中的对象执行了一次浅复制
  • 寄生式继承

    创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function createAnother(original){
    var clone = object(original); //通过调用函数创建一个新对象
    clone.sayHi = function(){ //以某种方式来增强这个对象
    alert("hi");
    };
    return clone; //返回这个对象
    }

    var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
    };

    var anotherPerson = createAnother(person);
    anotherPerson.sayHi(); //"hi"
    • 使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率;这一点与构造函数模式类似。
  • 寄生组合式继承

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    function inheritPrototype(Child, Parent){
    var prototype = object(Parent.prototype); //创建对象
    prototype.constructor = Child; //增强对象
    Child.prototype = prototype; //指定对象
    }

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

    Parent.prototype.sayName = function(){
    alert(this.name);
    };

    function Child(name, age){
    Parent.call(this, name); // 构造函数继承属性
    this.age = age;
    }

    inheritPrototype(Child, Parent); // 继承原型上的方法

    Child.prototype.sayAge = function(){
    alert(this.age);
    };
    • 第一步是创建超类型原型的一个副本。
    • 第二步是为创建的副本添加constructor属性,从而弥补因重写原型而失去的默认的constructor属性。
    • 最后一步,将新创建的对象(即副本)赋值给子类型的原型。
0%