详解JavaScript ES5的五大继承方式及优缺点

作者:木棉时间:2026-10-23 19:47:52浏览:247

本文详细解析JavaScript ES5环境下的五种继承实现方式,包括对象冒充、原型链、组合、原型式及寄生式继承。通过对比ES6的extends语法,深入剖析各方式在构造函数执行次数、原型方法共享及参数传递上的差异,重点讲解寄生式继承如何实现近乎完美的ES5继承效果,并探讨其在面试与实际开发中的应用场景。

ES6与ES5继承概述

随着ES6标准的普及,ES5的继承机制在实际开发中已较少使用,但在技术面试中仍常被考察。

首先回顾ES6的继承实现。


class Father{

      constructor(a){
        console.log(a);
      }
      play(){
        console.log("aaa");
      }
      static run(){
        console.log("static");
      }
    }
    class Son extends Father{
      constructor(){
        super();
      }
    }
    var s=new Son();
    s.play();
    Father.run()
    Son.run();

在ES6规范中,仅需使用extends关键字和super函数即可轻松继承父类的实例属性、方法以及静态成员。

相比之下,ES5标准中并不存在这些便捷关键字。

接下来探讨ES5环境下的继承实现。

ES5中主要存在五种继承模式:

  1. 第一种是对象冒充继承。
  2. 第二种是原型链继承。
  3. 第三种是组合继承。
  4. 第四种是原型式继承。
  5. 第五种是寄生式继承,该方式被视为较完美的方案。

对象冒充继承

对象冒充继承的核心在于利用call或apply方法改变this指向,从而执行父类的构造函数。


function Father(_r){
      this.r=_r;
      console.log("aa");
      console.log(this.r);
    }
    Father.a=3;
    Father.run=function(){
      console.log(Box.a);
    }
function Son(){
      Father.call(this,3);//改变this的指向,执行父类构造函数并传参到父类
    }
    var b=new Son();//"aa",3
    b.run();//TypeError

这种方式的局限性在于,它仅能继承父类的构造函数逻辑,无法获取原型链上定义的方法。

其缺点明确:子类无法访问父类原型链上的方法,仅能继承构造函数部分。

原型链继承

第二种模式为原型链继承。


function Father(){
  console.log("aa");
    }
Father.prototype.b=10;
    Father.prototype.play=function(){
      console.log(this.b);
    }
    Son.prototype=new Father();
    function Son(){
    }
    var b=new Son();
    b.play();//10

其实现原理是将父类的实例对象赋值给子类的原型属性,以此建立继承关系。

该方式的主要缺陷在于会覆盖子类原有的属性和方法,导致只能执行父类的属性和方法,且无法在继承过程中执行父类的构造函数。

组合继承

第三种模式称为组合继承。

鉴于前两种继承方式(对象冒充与原型链)各有优劣,将二者结合使用的方案被称为组合继承。


function Father(_r){
      this.r=_r;
      console.log("aa");
    }
function Son(_r){
      Father.call(this,_r);//冒充,改变父类的this指向子类
    }
Son.prototype=new Father(3);//原型链继承
 var c=new Son(10);

具体实现上,它利用原型链来继承父类的属性和方法,同时通过对象冒充来继承父类的构造函数。

尽管看似完善,但这并非理想的继承方案。

其核心缺点在于会覆盖子类原有属性和方法,因为原型链继承需提前实例化父类,导致父类构造函数被执行一次;随后子类实例化时再次执行父类构造函数,总计执行两次。

适用场景主要限于子类原本无属性和方法,且父类构造函数内部无具体逻辑的情况。

原型式继承

第四种模式为原型式继承。

为解决构造函数被执行两次的问题,原型式继承引入中介对象,使得在继承过程中不直接执行父类构造函数。


function Father(_a){
      this.a=_a
    }
    Father.prototype.play=function(){
      console.log("aaa");
    }
      function Agent(){

      }
      Agent.prototype=Father.prototype;
      function Son(){

      }
      Son.prototype=new Agent();
      var o=new Son();
      o.play();//aaa

该方式利用一个中介类(如Agent),将父类的原型复制给中介类,随后进行实例化继承,从而避免执行父类构造函数。

尽管解决了构造函数执行两次的问题,但该方法的副作用是构造函数一次也不会被执行。

寄生式继承

第五种模式为寄生式继承,常被视为ES5下的完美继承方案。

该方案封装了一个extend函数,接收父类和子类作为两个参数。


function extend(subClass, supClass) {
     function Agent() {}
     Agent.prototype = supClass.prototype;
     var o = subClass.prototype;
     subClass.prototype = new Agent();
     if (Object.assign) {
      Object.assign(subClass.prototype, o);
     } else {
      if (Object.getOwnPropertyNames) {
       var names = Object.getOwnPropertyNames(o);
       for (var i = 0; i < names.length; i++) {
        var desc = Object.getOwnPropertyDescriptor(names[i]);
        Object.defineProperty(subClass.prototype, names[i], desc);
       }
      } else {
       for (var prop in o) {
        subClass.prototype[prop] = o[prop];
       }
      }
     }
     subClass.prototype.constructor = subClass; //防止子类的构造函数被覆盖
     if (supClass.prototype.constructor === Object) {
      supClass.prototype.constructor = supClass; //防止父类类的构造函数被覆盖
     }
     // 存储父类,方便继承构造函数调用
     subClass.prototype.superClass = supClass;
    }
 //调用
    function Father(_r) {
     this.r = _r;
     console.log("Father");
    }
    Father.prototype.play = function () {
     console.log("play game");
    };
    function Ball(_r) {
     this.superClass.call(this, _r);
    }
    var s = new Son(10);//Father
    s.play();//play game

在extend函数内部,由于Object.assign、Object.getOwnPropertyNames、Object.getOwnPropertyDescriptor及Object.defineProperty等方法存在浏览器兼容性问题,因此代码中加入了相应的兼容性判断逻辑。

该方法集合了前四种继承方式的优点,实现了ES5环境下近乎完美的继承效果。

总结来看。

与ES6的继承相比,ES5的继承实现过程繁琐复杂,且在实际工程项目中已极少使用。

然而,在面试场景中,面试官可能会考察相关知识,因此多掌握一些理论总无坏处。

以上即为详解JavaScript ES5继承的详细内容,更多关于JavaScript ES5继承的资料请关注本站其它相关文章!

作者最新文章