JavaScript 继承机制详解:从构造函数到 ES6 Class 的多种实现方式

作者:函数茶馆

时间:2026-10-22

浏览:218

本文系统梳理了 JavaScript 中实现继承的多种核心模式,涵盖构造函数继承、call/apply 借用、原型链继承以及混合继承策略,并深入解析 ES6 Class 语法的底层实现。通过拖拽示例等具体代码演示,对比各方案的优缺点与适用场景,帮助开发者深入理解 JS 面向对象编程中的继承机制。

文章目录

JavaScript 继承概述

尽管 JavaScript 并非如 Java 那般具备严格的强类型系统,但它同样支持并实现了类似 Java 的继承特性。本文将探讨在 JavaScript 中实现继承的具体方法与原理。

构造函数与借用继承

一、构造函数继承


在构造函数中,同样属于两个新创建的函数,也是不相等的
 function Fn(name){
  this.name = name;
  this.show = function(){
   alert(this.name);
  }
 }
 var obj1 = new Fn("AAA");
 var obj2 = new Fn("BBB");
 console.log(obj1.show==obj2.show);  //false
 此时可以看出构造函数的多次创建会产生多个相同函数,造成冗余太多。
 利用原型prototype解决。首先观察prototype是什么东西
 function Fn(){}
 console.log(Fn.prototype);
 //constructor表示当前的函数属于谁
 //__proto__ == [[prototype]],书面用语,表示原型指针
 var fn1 = new Fn();
 var fn2 = new Fn();
 Fn.prototype.show = function(){
  alert(1);
 }
 console.log(fn1.show==fn2.show);  //ture
 此时,任何一个对象的原型上都有了show方法,由此得出,构造函数Fn.prototype身上的添加的方法,相当于添加到了所有的Fn身上。

二、利用 call 和 apply 实现继承


function Father(skill){
  this.skill = skill;
  this.show = function(){
   alert("我会"+this.skill);
  }
 }
 var father = new Father("绝世木匠");
 function Son(abc){
  //这里的this指向函数Son的实例化对象
  //将Father里面的this改变成指向Son的实例化对象,当相遇将father里面所有的属性和方法都复制到了son身上
  //Father.call(this,abc);//继承结束,call适合固定参数的继承
  //Father.apply(this,arguments);//继承结束,apply适合不定参数的继承
 }
 father.show()
 var son = new Son("一般木匠");
 son.show();

原型链继承实现

三、原型链继承(含示例)

以下示例展示了一个简单的拖拽功能实现,旨在演示如何将对象 a 的功能继承给对象 b,即实现从 a 到 b 的继承关系。

HTML 结构如下:


 <div id="drag1"></div>
 <div id="drag2"></div>

CSS 样式定义如下:


*{margin: 0;padding: 0;}
 #drag1{width: 100px;height: 100px;background: red;position: absolute;}
 #drag2{width: 100px;height: 100px;background: black;position: absolute;left: 500px;}

JavaScript 逻辑代码如下:


function Drag(){}
  Drag.prototype={
   constructor:Drag,
   init:function(id){
    this.ele=document.getElementById(id);
    this.cliW=document.documentElement.clientWidth||document.body.clientWidth;
    this.cliH=document.documentElement.clientHeight||document.body.clientHeight;
    var that=this;
    this.ele.onmousedown=function(e){
     var e=event||window.event;
     that.disX=e.offsetX;
     that.disY=e.offsetY;
     document.onmousemove=function(e){
      var e=event||window.event;
      that.move(e);
     }
     that.ele.onmouseup=function(){
      document.onmousemove=null;
     }
    }  
   },
   move:function(e){
    this.x=e.clientX-this.disX;
    this.y=e.clientY-this.disY;
    this.x=this.x<0?this.x=0:this.x;
    this.y=this.y<0?this.y=0:this.y;
    this.x=this.x>this.cliW-this.ele.offsetWidth?this.x=this.cliW-this.ele.offsetWidth:this.x;
    this.y=this.y>this.cliH-this.ele.offsetHeight?this.y=this.cliH-this.ele.offsetHeight:this.y;
    this.ele.style.left=this.x+'px';
    this.ele.style.top=this.y+'px';
   }
  }
  new Drag().init('drag1')
  function ChidrenDrag(){}
  ChidrenDrag.prototype=new Drag()
  new ChidrenDrag().init('drag2')

混合继承与 ES6 Class

四、混合继承模式


function Father(skill,id){
  this.skill = skill;
  this.id = id;
 }
 Father.prototype.show = function(){
  alert("我是father,这是我的技能"+this.skill);
 }
 function Son(){
  Father.apply(this,arguments);
 }
 //如果不做son的原型即成father的原型,此时会报错:son.show is not a function
 Son.prototype = Father.prototype;
 //因为,如果不让son的原型等于father的原型,son使用apply是继承不到原型上的方法
 //但这是一种错误的原型继承示例,如果使用这种方式,会导致修改son原型上的show方法时,会把father身上的show也修改
 //内存的堆和栈机制
 Son.prototype.show = function(){
  alert("我是son,这是我的技能"+this.skill);
 }
 var father = new Father("专家级铁匠","father");
 var son = new Son("熟练级铁匠","son");
 father.show();
 son.show();
 上面的示例应该修改成以下形式:
 以上红色的代码应改成:
 for(var i in Father.prototype){
  Son.prototype[i] = Father.prototype[i];
 }
 //遍历father的原型身上的所有方法,依次拷贝给son的原型,这种方式称为深拷贝
 这种继承方式叫做混合继承,用到了for-in继承,cell和apple继承。

五、ES6 Class 继承(含示例)

该示例的功能与前述原型链继承的示例一致,同样演示了从对象 a 到对象 b 的继承过程。

HTML 结构如下:


 <div id="drag1"></div>
 <div id="drag2"></div>

CSS 样式定义如下:


 *{margin: 0;padding: 0;}
 #drag1{width: 100px;height: 100px;background: red;position: absolute;}
 #drag2{width: 100px;height: 100px;background: black;position: absolute;left: 500px;}

JavaScript 逻辑代码如下:


class Drag{
   constructor(id){
    this.ele=document.getElementById(id);
    this.init();
   };
   init(){
    var that=this;
    this.ele.onmousedown=function(e){
     var e=event||window.event;
     that.disX=e.offsetX;
     that.disY=e.offsetY;
     document.onmousemove=function(e){
      var e=event||window.event;
      that.move(e);
     }
     that.ele.onmouseup=function(){
      document.onmousemove=null;
      that.ele.onmouseup=null;
     }
    }
   };
   move(e){
    this.ele.style.left=e.clientX-this.disX+"px";
    this.ele.style.top=e.clientY-this.disY+"px";
   }
  }
  new Drag("drag1");
  class ExtendsDrag extends Drag{
   constructor(id){
    super(id);
   }
  }
  new ExtendsDrag("drag2")

综上所述,本文介绍了多种继承实现方法。建议读者在代码编译器中实际运行这两个示例,通过实践加深理解。特别是原型链继承,作为 JavaScript 这一面向对象编程语言中常用的技术,掌握其原理至关重要。

总结

以上内容介绍了 JavaScript 中的继承机制及相关实现代码,希望能对读者有所帮助。如有任何疑问,欢迎留言,小编会及时回复。感谢大家对本站的支持!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章