Skip to content

JS基础-02:继承


常用继承方式


概要内容

方式一:调整类型原型的__proto__ 、 Object.setPrototypeOf 、Object.create

jsx
function Animal(name){
        this.name = name;
        this.arr = [1,2,3];
    }

    Animal.prototype.address = {location:"山里"};

    function Tiger(name){
        this.name = name;
        this.age = 10;
        Animal.call(this,this.name);
    }
  
    Tiger.prototype.__proto__ = Animal.prototype; 
    // 等同 es7 方法:Object.setPrototypeOf(Tiger.prototype,Animal.prototype);
  // or Tiger.prototype = Object.create(Animal.prototype);

    Tiger.prototype.say = function(){
        return "说话";
    }

    let tiger = new Tiger("xxx");
    console.log(`父类实例属性:${tiger.arr}`);//父类实例属性:1,2,3
    console.log(`父类原型属性:${JSON.stringify(tiger.address)}`);//父类原型属性:{"location":"山里"}
    console.log(`子类实例属性:${tiger.age}`);//子类实例属性:10
    console.log(`子类原型属性:${tiger.say()}`);//子类原型属性:说话

方法二:利用自定义createObject

jsx
function Animal(name){
        this.name = name;
        this.arr = [1,2,3];
    }

    Animal.prototype.address = {location:"山里"};

    function Tiger(name){
        this.name = name;
        this.age = 10;
        Animal.call(this,this.name);
    }

    function createObject(parentPrototype){
        function Fn(){}
        Fn.prototype = parentPrototype;
        return new Fn();
    }

    Tiger.prototype = createObject(Animal.prototype);
    Tiger.prototype.say = function(){
        return "说话";
    }

    let tiger = new Tiger("xxx");
    console.log(`父类实例属性:${tiger.arr}`);//父类实例属性:1,2,3
    console.log(`父类原型属性:${JSON.stringify(tiger.address)}`);//父类原型属性:{"location":"山里"}
    console.log(`子类实例属性:${tiger.age}`);//子类实例属性:10
    console.log(`子类原型属性:${tiger.say()}`);//子类原型属性:说话

方式三:利用ES6 Class extends

jsx
class Animal {
        address = {location:"山里"};
        constructor(name){
            this.name = name;
            this.arr = [1,2,3];
        }
    }
    
    class Tiger extends Animal {
        constructor(name){
           super(name);
           this.age = 10;
        }

        say(){
            return "说话";
        }
    }

    let tiger = new Tiger("xxx");
    console.log(`父类实例属性:${tiger.arr}`);//父类实例属性:1,2,3
    console.log(`父类原型属性:${JSON.stringify(tiger.address)}`);//父类原型属性:{"location":"山里"}
    console.log(`子类实例属性:${tiger.age}`);//子类实例属性:10
    console.log(`子类原型属性:${tiger.say()}`);//子类原型属性:说话
  1. 子类不写constructor时,创建子类实例时,会默认调用父类构造方法

    jsx
    class Animal {
     constructor() {
      console.log("Animal.constructor");
     }
    }
    
    class Person extends Animal {
    }
    
    let p = new Person();
    //输出:Animal.constructor
  2. 子类写了构造函数,然后继承了父类, 就必须在构造函数调用super or 返回一个对象

    jsx
    class Animal {
     constructor() {
      console.log("Animal.constructor");
     }
    }
    
    class Person extends Animal {
     //! 说明:子类不写constructor时,创建子类实例时,会默认调用父类构造方法
     constructor() {
      //console.log(this);
      //! 子类写了构造函数,然后继承了父类, 就必须在构造函数调用super 
      //! 注意:super之前不要引用this, 否则会报错:Must call super constructor in derived class before accessing 'this' or returning from derived constructor
      super();
      console.log("Person.constructor")
    
      //! 或者:返回一个对象
      // return { name: "Person" }
     }
    }
    
    let p = new Person();

总结

  • 推荐使用es6的class来进行继承(注意:继承链不宜过长,否则会导致性能问题。更多细节:继承与原型链
  • 不推荐通过改变类型原型的__proto__指向的方式(兼容性不好,而且将 __proto__ 设置为非对象的值会静默失败,不会抛出错误。更多细节:继承与原型链

...

以上:如发现有问题,欢迎留言指出,我及时更正

Released under the MIT License.