最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript 中的这些继承方式,你弄懂了吗?

    正文概述 掘金(Twittytop)   2021-05-18   445

    前言

    ES6 以前,JavaScript 中的继承不像其它 oo 语言一样,用特定 class 去实现,它是由构造函数和原型去模拟,下面我们会介绍几种常见的继承方法以及对应的优点和不足。

    原型链

    什么是原型链?

    比如我有一个构造函数,这个构造函数的实例有一个内部指针[[Prototype]]指向构造函数的原型,然后这个构造函数的原型又是另一个构造函数的实例,也就是说这个构造函数原型有一个内部指针[[Prototype]]指向另一个构造函数的原型,如此下去,就构成了一条原型链。那用原型链实现继承用代码表示出来就是这样:

    function Parent () {
        this.name = 'Twittytop';
    }
    Parent.prototype.getName = function () {
        return this.name;
    }
    function Child () {
        this.age = 29;
    }
    // 继承
    Child.prototype = new Parent();
    var ins = new Child();
    console.log(ins.getName()); // Twittytop
    

    这样原来在 Parent 上的属性都变成了 Child.prototype 上的属性。

    JavaScript 中的这些继承方式,你弄懂了吗?

    问题

    第一:共享问题

    当 Parent 上包含有引用属性时,就出出现问题,比如:

    function Parent () {
        this.friends = ['Jack', 'Tom'];
    }
    function Child () {
        this.age = 29;
    }
    // 继承
    Child.prototype = new Parent();
    var ins1 = new Child();
    ins1.friends.push('Bob');
    var ins2 = new Child();
    console.log(ins2.friends); // ["Jack", "Tom", "Bob"]
    

    因为继承之后变成了 Child 的原型属性,所以所有 Child 的实例都指向的是同一个 friends,当其中一个实例修改了这个值之后,变化就会反映到所有实例上。

    第二: 传参问题

    Child 在实例化是没法向 Parent 传参,当 Parent 依赖外部传参时,就会导致问题。

    盗用构造函数

    function Parent (name) {
        this.name = name;
    }
    Parent.prototype.getName = function () {
        return this.name;
    }
    function Child (name, age) {
        // 继承
        Parent.call(this, name);
        this.age = age;
    }
    var ins = new Child('Twittytop', 29);
    console.log(ins.name); // Twittytop
    console.log(ins.getName); // undefined
    

    可以看到,盗用构造函数的优点是能传递参数,问题是它只能继承实例属性,不能继承原型属性。

    组合继承

    既然原型链和盗用构造函数继承都有各自的缺点,那我们能不能把这两者结合起来呢?这就是组合继承。

    function Parent (name) {
        this.name = name;
    }
    Parent.prototype.getName = function () {
        return this.name;
    }
    function Child (name, age) {
        // 继承实例属性
        Parent.call(this, name);
        this.age = age;
    }
    // 继承原型属性
    Child.prototype = new Parent();
    var ins = new Child('Twittytop', 29);
    console.log(ins.name); // Twittytop
    console.log(ins.getName()); // Twittytop
    

    组合继承弥补了原型链和盗用构造函数的不足,能同时继承实例属性和原型属性,但它的缺点是会调用两次父类构造函数。一次是在 Child 构造函数中执行 Parent.call,一次是在实例化 Parent 时。这样就会导致 Child 的不仅自身实例上有 name 属性,原型上也有 name 属性,导致了不必要的多余继承。用图表示如下:

    JavaScript 中的这些继承方式,你弄懂了吗?

    原型式继承

    function Parent (name) {
        this.name = 'Twittytop';
    }
    Parent.prototype.getName = function () {
        return this.name;
    }
    function Child (age) {
        this.age = age;
    }
    // 继承原型属性
    Child.prototype = Object.create(Parent.prototype);
    var ins = new Child(29);
    console.log(ins.getName);
    

    原型式继承只继承了原型上的属性,没有继承实例属性,相比原型链继承更干净,它没有把父类的实例属性继承到自身的原型上面,当然,它和原型链一样,也会有引用属性的共享问题。

    寄生式继承

    寄生式继承是建立在原型式继承基础上的,寄生式继承用代码表达出来是这样:

    function inherit (Parent) {
        let pro = Object.create(Parent.prototype);
        pro.myMethod = function () {};
        return pro;
    }
    

    它相比原型式继承多了添加一些自己的属性和方法。

    寄生式组合继承

    寄生式组合继承综合了盗用构造函数和寄生式继承,它使用盗用构造函数继承实例属性,使用寄生式继承继承原型属性。

    function inherit (Child, Parent) {
        let pro = Object.create(Parent.prototype);
        pro.constructor = Child; // 将constructor重新指回Child
        Child.prototype = pro;
    }
    function Parent (name) {
        this.name = name;
    }
    Parent.prototype.getName = function () {
        return this.name;
    }
    function Child (name, age) {
        // 继承实例属性
        Parent.call(this, name);
        this.age = age;
    }
    // 继承原型属性
    inherit(Child, Parent)
    var ins = new Child('Twittytop', 29);
    console.log(ins.name); // Twittytop
    console.log(ins.getName()); // Twittytop
    

    寄生式组合继承吸取了盗用构造函数和寄生式继承的优点,又没有组合继承中调用父类构造函数两次的不足,是ES5 实现继承的最佳模式。

    关于 ES6 的继承,这里就不介绍了,它本质是上述继承的语法糖而已。

    写在后面

    JavaScript 继承独特的地方就是它的原型,如果这篇文章能让你对 JavaScript 继承有进一步的了解,那将是我最大的欣慰。如果你觉得能学到一点东西的话,还请动动你可爱的小指让更多人看到。如果有错误或者有疑问的地方,也欢迎交流讨论。


    起源地下载网 » JavaScript 中的这些继承方式,你弄懂了吗?

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元