美文网首页面试宝典
2020-09-24(js的继承方式)

2020-09-24(js的继承方式)

作者: 宇宙区长李小无 | 来源:发表于2020-09-24 19:56 被阅读0次

    前言

    两天没写了,靠,怎么这么懒,废话不多说,来了来了。

    继承

    子类能够享有父类所拥有的属性和方法,在创建类似实例的时候非常有用。

    原型链继承

    不知道大家有没有搞清楚构造函数、实例对象、原型对象之间的关系,其实构造函数也是一个对象,js一切皆对象嘛,function也是通过new Function()来创建的,而且
    Function.prototype.__proto__ === Object.prototype
    我想说的是:每个实例对象都是通过__proto__指针来与其构造函数的原型对象进行关联的,访问属性时就是按照这条原型链。

    第一种继承:简单的获取到父类的属性和方法

    function Parent(name) {
        this.name = name || 'parentName';
    }
    Parent.prototype.sayName = function () {
        console.log(this.name);
    }
    
    function Son(age) {
        this.age = age;
    }
    Son.prototype = new Parent();
    const son1 = new Son(18);
    
    
    • 原理:
      instance.__proto__ == constructor.prototype;上面说的关系链
    • 缺点:
      • 所有实例共享父类的属性和方法,一旦子类修改自身prototype的 属性,其他子类也会受到影响
      • 只能继承一个父类
      • 子类在创建实例的时候无法向父类传参
      • 子类想要添加自己的原型方法和属性必须在继承之前操作

    借用构造函数继承

    子类在创建实例时可以传递参数给父类

    function Parent(name) {
        this.name = name || 'parentName';
    }
    Parent.prototype.sayName = function () {
        console.log(this.name);
    }
    
    function Son(name, age) {
        Parent.call(this, name);
        this.age = age;
    }
    son1 = new Son("carter", 18);
    
    • 原理:
      call方法执行父类的方法,添加父类本身属性给子类
    • 缺点:
      • 每个子类实例都需要调用父类构造函数
      • 无法继承父类的原型中的属性和方法
      • 并不属于父类的实例,只属于子类

    原型加借用构造函数继承

    前面两种方法的综合,借助原型链继承父类的原型属性和方法,借用构造函数(可以传参),继承父类的属性和方法,不存在共享属性的问题。

    function Parent(name) {
        this.name = name || 'parentName';
    }
    Parent.prototype.sayName = function () {
        console.log(this.name);
    }
    
    function Son(name, age) {
        Parent.call(this, name);
        this.age = age;
    }
    Son.prototype = new Parent();
    son1 = new Son("carter", 18);
    
    
    
    

    缺点:

    • 需要调用两次构造函数
    • 需要重写子类原型的constructor属性

    组合式继承

    遇上述方法不同的是,在继承原型属性时,直接将子类原型对象指向父类的原型对象,这样就不需要调用两次构造函数了。

    function Parent(name) {
        this.name = name || 'parentName';
    }
    Parent.prototype.sayName = function () {
        console.log(this.name);
    }
    
    function Son(name, age) {
        Parent.call(this, name);
        this.age = age;
    }
    Son.prototype = Parent.prototype;
    son1 = new Son("carter", 18);
    
    

    缺点:

    • 子类实例的constructor属性指向不对

    寄生式组合继承

    与组合式继承不同的是,在继承原型属性时,完全复制一个父类的原型对象指向子类原型。重写constructor。

    function Parent(name) {
        this.name = name || 'parentName';
    }
    Parent.prototype.sayName = function () {
        console.log(this.name);
    }
    
    function Son(name, age) {
        Parent.call(this, name);
        this.age = age;
    }
    Son.prototype = Object.create(Parent.prototype);
    Son.prototype.constructor = Son;
    // Object.create原理:
    // Object.create = function (protoObj) {
    //  function F() {};
    //  F.prototype = protoObj;
    //  return new F();
    // }
    son1 = new Son("carter", 18);
    
    

    ES6的class继承

    class Parent {
        constructor(name) {
            this.name = name;
        }
        sayName() {
            console.log(this.name);
        }
    }
    
    class Son extends Parent {
        constructor(name, age) {
            super(name);
            this.age = age;
        }
    }
    son1 = new Son("carter", 18);
    
    

    总结

    ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

    相关文章

      网友评论

        本文标题:2020-09-24(js的继承方式)

        本文链接:https://www.haomeiwen.com/subject/eextuktx.html