Javascript继承知多少?

  发布时间:2025-11-05 08:47:59   作者:玩站小弟   我要评论
1写在前面我们知道面向对象的编程语言中都会有继承,而且在各种语言中充当着至关重要的角色,但是继承是什么?又有多少种继承的方式?常见的又有哪些呢?对于js继承有更深层次的理解,能够在开发中应对自如。所谓 。

1写在前面

我们知道面向对象的继承编程语言中都会有继承,而且在各种语言中充当着至关重要的知多角色,但是继承继承是什么?又有多少种继承的方式?常见的又有哪些呢?对于js继承有更深层次的理解,能够在开发中应对自如。知多

所谓继承,继承继承是知多面向对象的,使用这种方式能够更好的继承对代码的复用,能够缩短开发周期、知多提升开发效率。继承

那么我们带着两个问题阅读文章,知多在文章解决这些疑惑:

JS继承到底有多少种继承方式?继承 ES6中的extends关键字是使用哪种继承方式实现的?

2继承的概念

我们知道一个人继承祖业,可以将父辈所有的知多物质基础继承过来,但是继承自己作为主体又有自己的其它能力和特性。同样的知多汽车作为一个大类,生产轿车、网站模板继承跑车、面包车等,都具有汽车四个轮子加发动机的特性,但各自具有自己独特的特性,比如五菱宏光可以在秋名山飙车成为车神。

因此,继承可以使得子类具有父类的各种方法和属性。

常见的继承方式有:

原型链继承 构造函数继承 组合继承 原型链继承 寄生式继承 寄生组合式继承

3继承

3.1 原型链继承

原型链继承是比较常见的继承方式之一,其中涉及的构造函数、原型和实例:

每个构造函数都有一个原型对象 原型对象又包含一个指向构造函数的指针 实例则包含一个原型对象的指针 function Person(){     this.name = "person";     this.abilities = ["吃饭","睡觉","打豆豆"]; } function Student(){     this.study = ["语文","数学","英语"]; } Student.prototype = new Person(); console.log(new Student()); 

我们可以看到Student类已经继承了Person类的所有特性:

但是,我们注意到:当使用同一个对象创建实例的时候,内存空间是共享的,当一个发生变化的时候,另外一个也会随之变化。

function Person(){     this.name = "person";     this.abilities = ["吃饭","睡觉","打豆豆"]; } function Student(){     this.study = ["语文","数学","英语"]; } Student.prototype = new Person(); const stu1 = new Student(); const stu2 = new Student(); stu1.abilities.push("走路"); console.log(stu1.abilities,stu2.abilities); 

我们看到stu1和stu2都是由Student对象进行创建的两个实例,当改变stu1的服务器托管值,stu2的值也随之改变了。图片

3.2 构造函数继承(借助call)

构造函数继承可以很好的解决原型链继承的共享内存的弊端,但是父类原型对象中存在父类之前自己定义的方法,那么子类将无法继承这些方法,此时去使用父类方法就会报错。

构造函数继承只能继承父类实例、属性和方法,不能继承原型属性和方法。

function Person(){     this.name = "person"; } Person.prototype.getName = function(){     return this.name; } function Student(){     Person.call(this);     this.study = ["语文","数学","英语"]; } const stu = new Student(); console.log(stu); console.log(stu.getName()) 

我们可以看到,打印的stu实例包含了Student对象以及父类Person所有的属性,但是要使用父类原型的方法就会报错。getName是父类Person的引用方法,不会共享内存。

3.3 组合继承(原型链继承+构造函数继承)

function Person(){     this.name = "person";     this.abilities = ["吃饭","睡觉","打豆豆"]; } //第一次调用Person() Person.prototype.getName = function(){     return this.name; } function Student(){   //第二次调用Person()     Person.call(this);     this.study = ["语文","数学","英语"]; } Student.prototype = new Person(); //手动挂载构造器,指向自己的构造函数 Student.prototype.constructor = Student; const stu1 = new Student(); const stu2 = new Student(); stu1.abilities.push("走路"); console.log(stu1.abilities,stu2.abilities);//不会互相影响 console.log(stu1.getName());//正常输出"person" console.log(stu2.getName());//正常输出"person" 

运行得到:我们看到在stu1实例的abilities数组中追加元素,并不会影响到stu2实例的值。图片我们发现使用组合式继承时,企商汇可以有效解决原型链继承和构造函数继承的缺点,但是,调用两次Person(),这就造成了性能开销,那么我们还有没有优化空间呢?

3.4 原型式继承

我们可以利用es5中的Object.create()方法进行原型式继承,从而实现对组合式继承的优化。Object.create()接收两个参数:

用作新对象原型的对象

为新对象定义额外属性的对象(可选参数)

const person = {     name:"person",     abilities:["吃饭","睡觉","打豆豆"],     getName(){         return this.name;     } } const person1 = Object.create(person); person1.name = "human"; person1.abilities.push("走路"); const person2 = Object.create(person); person2.abilities.push("跑步"); console.log(person1.name); console.log(person1.name === person1.getName()); console.log(person2.name); console.log(person1.abilities); console.log(person2.abilities); 

我们可以看到使用Object.create()可以实现普通对象继承,不仅可以继承属性,还能继承方法。但是也有缺点:包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样。

修改person1.name的值,person2.name的值并未发生改变,并不是因为person1和person2有独立的 name 值,而是因为person1.name = human,给person1添加了 name 值,并非修改了原型上的 name 值。

3.5 寄生式继承

寄生式继承:首先使用原型式继承可以获得一份目标对象的浅拷贝,然后利用这个浅拷贝的能力再进行增强,添加一些方法。

寄生式继承相比于原型式继承,还是在父类基础上添加了更多方法。

function clone(original){     const clone = Object.create(original);     clone.getAbilities = function(){    return this.abilities;     }     return clone; } const person = {     name:"person",     abilities:["吃饭","睡觉","打豆豆"],     getName(){         return this.name;     } } const person1 = clone(person); console.log(person1.getName()); console.log(person1.getAbilities()); 

运行得到:

3.6 寄生组合式继承

前面分析了五种常见的继承方法,现在综合所有方式的优缺点,可以进行优化改造得到寄生组合式的继承方式,这也是所有继承方式中相对最优的。

function clone(parent,child){     //这里使用Object.create()可以减少组合继承中多进行一次构造函数的过程     child.prototype = Object.create(parent.prototype);     child.prototype.constructor = child; } function Parent(){     this.name = "parent";     this.abilities = ["吃饭","睡觉","打豆豆"]; } Parent.prototype.getName = function(){     return this.name; } function Child(){     Parent.call(this);     this.study = ["语文","数学","英语"]; } clone(Parent,Child); Child.prototype.getStudy =function(){     return this.study; } const child = new Child(); console.log(child); console.log(child.getName()); console.log(child.getStudy()); 

运行得到:

extends关键字主要用于类声明或者类表达式中,以创建一个类,该类是另一个类的子类。其中constructor表示构造函数,一个类中只能有一个构造函数,有多个会报出SyntaxError错误,如果没有显式指定构造方法,则会添加默认的 constructor方法,使用例子如下。

class Rectangle {     // constructor     constructor(height, width) {         this.height = height;         this.width = width;     }     // Getter     get area() {         return this.calcArea()     }     // Method     calcArea() {         return this.height * this.width;     } } const rectangle = new Rectangle(10, 20); console.log(rectangle.area); // 输出 200 ----------------------------华丽的分割线------------------------------------- // 继承 class Square extends Rectangle {   constructor(length) {     super(length, length);     // 如果子类中存在构造函数,则需要在使用“this”之前首先调用 super()。     this.name = Square;   }   get area() {     return this.height * this.width;   } } const square = new Square(10); console.log(square.area); // 输出 100 

extends继承的核心代码如下,其实现和上述的寄生组合式继承方式一样。

function _inherits(subType, superType) {     // 创建对象,创建父类原型的一个副本     // 增强对象,弥补因重写原型而失去的默认的constructor 属性     // 指定对象,将新创建的对象赋值给子类的原型     subType.prototype = Object.create(superType && superType.prototype, {         constructor: {             value: subType,             enumerable: false,             writable: true,             configurable: true         }     });     if (superType) {         Object.setPrototypeOf              ? Object.setPrototypeOf(subType, superType)              : subType.__proto__ = superType;     } } 

4参考文章

《JavaScript常用八种继承方案》

《深入JavaScript继承原理》

5写在最后

继承的方法很多,每个实现的方法都比较零散,需要对常见的继承方法进行一个深入系统的分析总结。图片

  • Tag:

相关文章

  • 电脑官方插件的使用教程(轻松掌握官方插件的安装和使用方法)

    摘要:在现代的电脑操作中,插件已经成为了不可或缺的一部分。插件可以扩展电脑软件的功能,让用户能够更加个性化地使用电脑。而在众多插件中,电脑官方插件是用户最为信赖和依赖的,因为它们来自于软...
    2025-11-05
  • SCSS 中这些技巧,你可能还不知道!

    随着css工程化的普及,sass在前端工程中越来越举足轻重。当然sass并不局限于管理css全局变量、mixin之类的"脏活累活"。这篇文章会跟随工程化前端一步一步记录sass中那些不为人知,但是又非
    2025-11-05
  • API类型和集成规范指南

    在我们的常见应用中,往往包含着大量服务于各种数据交换的API类型、以及各种常见的API架构与协议。下面,我将从集成的角度和您讨论,在准备将多个服务相互集成时,使用不同类型、架构和协议的API意味着什么
    2025-11-05
  • Go 开发者 2021 调查报告

    Go 官方博客公布了 2021 年面向 Go 开发者的调查报告。据称此次调查收到了 11,840 份回复,问卷回收数量是调查发起 6 年来最多的一次。调查报告亮点大多数回复与往年
    2025-11-05
  • 常见的电脑设置错误及解决方法(避免电脑设置错误的关键注意事项)

    摘要:在现代社会中,电脑已经成为人们工作和生活中不可或缺的一部分。然而,许多人在使用电脑时常常遇到各种设置错误,导致电脑功能无法正常发挥。本文将探讨一些常见的电脑设置错误以及解决方法,帮...
    2025-11-05
  • Webpack 打包 Commonjs 和 Esmodule 模块的产物对比

    这篇文章不涉及 Webpack 的原理,只是观察下 Webpack 对 commonjs 和 esmodule 模块打包后的产物,读完后会对模块系统有个更深的了解。环境配置Web
    2025-11-05

最新评论