一文让你搞懂javascript如何实现继承
connygpt 2024-12-08 14:21 7 浏览
JavaScript继承详解:多种实现方法解析
在JavaScript中,继承是面向对象编程的一个核心概念。通过继承,子类能够获得父类的属性和方法,从而实现代码的重用和扩展。JavaScript提供了多种实现继承的方法,包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承以及ES6类继承。本文将对这些方法进行详细解析,帮助你全面理解JavaScript中的继承机制。
目录
- 原型链继承
- 构造函数继承
- 组合继承
- 原型式继承
- 寄生式继承
- ES6类继承
- 继承方法对比分析
- 总结
原型链继承
原型链继承是JavaScript中最基本的继承方式。它通过将子类的原型指向父类的一个实例,实现子类对父类属性和方法的继承。
实现步骤
- 定义父类构造函数,在其原型上添加属性和方法。
- 定义子类构造函数,使用 new关键字创建子类实例,并将父类实例赋值给子类的原型。
代码示例
// 定义父类
function Parent() {
this.name = 'Parent';
}
Parent.prototype.sayHello = function() {
console.log(`Hello from ${this.name}`);
};
// 定义子类
function Child() {
this.age = 18;
}
Child.prototype = new Parent(); // 继承父类
Child.prototype.constructor = Child; // 修正构造函数指向
// 使用子类
const child = new Child();
child.sayHello(); // 输出: Hello from Parent
console.log(child.age); // 输出: 18
详细解释
- 父类构造函数 Parent定义了一个属性 name,并在其原型上添加了方法 sayHello。
- 子类构造函数 Child定义了一个属性 age。
- 通过 Child.prototype = new Parent();,子类的原型指向了父类的一个实例,从而继承了父类的属性和方法。
- 修正构造函数指向 Child.prototype.constructor = Child;,确保 constructor属性指向子类自身。
优缺点
优点 | 缺点 |
简单易懂,实现快速 | 所有子类实例共享父类实例,导致属性共享,可能引发问题 |
子类实例可以访问父类原型上的方法和属性 | 无法向子类传递参数,无法实现多继承 |
构造函数继承
构造函数继承通过在子类构造函数中调用父类构造函数,使用 call或 apply方法,将父类的属性赋予子类实例,实现继承。
实现步骤
- 定义父类构造函数,在其中初始化属性。
- 定义子类构造函数,在其中调用父类构造函数,传递子类实例作为上下文。
代码示例
// 定义父类
function Parent(name) {
this.name = name;
}
Parent.prototype.sayHello = function() {
console.log(`Hello from ${this.name}`);
};
// 定义子类
function Child(name, age) {
Parent.call(this, name); // 继承父类属性
this.age = age;
}
// 使用子类
const child = new Child('Child', 18);
child.sayHello(); // 输出: Hello from Child
console.log(child.age); // 输出: 18
详细解释
- 父类构造函数 Parent接受一个参数 name,并将其赋值给实例属性 name。
- 子类构造函数 Child接受参数 name和 age,通过 Parent.call(this, name);调用父类构造函数,将 this指向子类实例,实现属性的继承。
- 子类自身定义了属性 age。
优缺点
优点 | 缺点 |
每个子类实例都有独立的父类属性,避免属性共享问题 | 无法继承父类原型上的方法和属性 |
可以向父类构造函数传递参数,增强灵活性 | 子类无法访问父类原型上的方法,需要结合其他继承方式 |
组合继承
组合继承结合了原型链继承和构造函数继承的优点,既继承了父类的属性,又继承了父类原型上的方法。
实现步骤
- 定义父类构造函数,初始化属性。
- 定义子类构造函数,调用父类构造函数,继承属性。
- 设置子类原型,通过原型链继承父类的方法。
代码示例
// 定义父类
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.sayHello = function() {
console.log(`Hello from ${this.name}`);
};
// 定义子类
function Child(name, age) {
Parent.call(this, name); // 继承属性
this.age = age;
}
Child.prototype = Object.create(Parent.prototype); // 继承方法
Child.prototype.constructor = Child;
// 使用子类
const child1 = new Child('Child1', 18);
child1.colors.push('yellow');
console.log(child1.colors); // 输出: ['red', 'blue', 'green', 'yellow']
child1.sayHello(); // 输出: Hello from Child1
const child2 = new Child('Child2', 20);
console.log(child2.colors); // 输出: ['red', 'blue', 'green']
child2.sayHello(); // 输出: Hello from Child2
详细解释
- 父类构造函数 Parent初始化属性 name和 colors数组,并在原型上定义方法 sayHello。
- 子类构造函数 Child通过 Parent.call(this, name);继承父类属性,同时定义自己的属性 age。
- 子类原型通过 Object.create(Parent.prototype);设置为父类的一个新实例,实现方法的继承。
- 修正构造函数指向 Child.prototype.constructor = Child;。
优缺点
优点 | 缺点 |
同时继承了父类的属性和方法 | 调用两次父类构造函数,存在性能开销 |
每个子类实例都有独立的父类属性 | 构造函数中无法继承父类的原型属性 |
原型式继承
原型式继承通过创建一个与父类实例关联的新对象,达到继承的目的。它使用一个临时构造函数,将父类实例作为其原型。
实现步骤
- 定义一个临时构造函数。
- 将父类实例赋值给临时构造函数的原型。
- 创建子类实例,继承父类属性和方法。
代码示例
// 定义父类
const parent = {
name: 'Parent',
sayHello() {
console.log(`Hello from ${this.name}`);
}
};
// 定义一个函数实现原型式继承
function createObject(obj) {
function F() {}
F.prototype = obj;
return new F();
}
// 使用原型式继承
const child = createObject(parent);
child.name = 'Child';
child.sayHello(); // 输出: Hello from Child
详细解释
- 定义了一个父类对象 parent,包含属性 name和方法 sayHello。
- createObject函数通过临时构造函数 F,将 parent对象赋值给 F.prototype,返回一个新的子类实例。
- 子类实例 child继承了父类的属性和方法,可以覆盖或扩展父类属性。
优缺点
优点 | 缺点 |
简单实现对象的继承 | 不能传递参数,所有子类实例共享父类对象 |
避免了引用类型属性的共享问题 | 子类实例无法识别父类构造函数,存在安全隐患 |
寄生式继承
寄生式继承在原型式继承的基础上,创建一个封装函数,在其中增强对象的功能,最终返回增强后的对象。
实现步骤
- 定义一个寄生函数,接受父类对象作为参数。
- 在寄生函数内部,使用原型式继承创建子类实例。
- 增强子类实例,添加新的属性或方法。
- 返回增强后的子类实例。
代码示例
// 定义父类
const parent = {
name: 'Parent',
sayHello() {
console.log(`Hello from ${this.name}`);
}
};
// 定义寄生式继承函数
function createChild(obj) {
const child = Object.create(obj);
child.age = 18;
child.sayAge = function() {
console.log(`I am ${this.age} years old`);
};
return child;
}
// 使用寄生式继承
const child = createChild(parent);
child.name = 'Child';
child.sayHello(); // 输出: Hello from Child
child.sayAge(); // 输出: I am 18 years old
详细解释
- 父类对象 parent包含属性 name和方法 sayHello。
- createChild函数通过 Object.create(obj)创建一个子类实例 child,继承父类的属性和方法。
- 在 child对象上新增属性 age和方法 sayAge,增强了子类的功能。
- 最终返回增强后的 child对象。
优缺点
优点 | 缺点 |
能够在继承的基础上增强子类功能 | 不能复用父类构造函数,无法继承父类的私有属性 |
实现简单,适用于需要扩展功能的场景 | 子类实例与父类实例之间存在紧密耦合 |
ES6类继承
ES6类继承是现代JavaScript中推荐的继承方式,通过 class和 extends关键字,实现类与类之间的继承关系,并使用 super关键字调用父类的构造函数和方法。
实现步骤
- 定义父类,使用 class关键字。
- 定义子类,使用 class和 extends关键字。
- 在子类构造函数中,使用 super调用父类构造函数。
- 在子类中定义自己的属性和方法。
代码示例
// 定义父类
class Parent {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello from ${this.name}`);
}
}
// 定义子类
class Child extends Parent {
constructor(name, age) {
super(name); // 调用父类构造函数
this.age = age;
}
sayAge() {
console.log(`I am ${this.age} years old`);
}
}
// 使用子类
const child = new Child('Child', 18);
child.sayHello(); // 输出: Hello from Child
child.sayAge(); // 输出: I am 18 years old
详细解释
- 父类 Parent使用 class关键字定义,包含构造函数 constructor和方法 sayHello。
- 子类 Child使用 class Child extends Parent定义,继承了 Parent的属性和方法。
- 在子类的构造函数中,通过 super(name);调用父类构造函数,传递参数 name。
- 子类新增了属性 age和方法 sayAge,扩展了父类的功能。
优缺点
优点 | 缺点 |
语法简洁,易于理解和使用 | 需要使用ES6以上的环境支持 |
通过 super关键字,明确调用父类构造函数 | 语法糖,底层仍基于原型链实现 |
支持类的静态方法和继承 | 过度依赖类的概念,可能限制灵活性 |
继承方法对比分析
为了更好地理解各种继承方法的特点,下面通过对比表进行分析。
继承方法 | 实现方式 | 继承属性 | 继承方法 | 是否可传递参数 | 是否共享引用类型属性 | 优点 | 缺点 |
原型链继承 | 子类原型指向父类实例 | 是 | 是 | 否 | 是 | 实现简单,方法共享 | 共享引用类型属性,无法向父类构造函数传参 |
构造函数继承 | 子类构造函数调用父类构造函数 | 是 | 否 | 是 | 否 | 每个实例独立,避免属性共享 | 无法继承父类原型方法 |
组合继承 | 同时使用原型链和构造函数继承 | 是 | 是 | 是 | 否 | 兼具两者优点,独立属性和共享方法 | 调用父类构造函数两次,性能开销 |
原型式继承 | 创建子类对象,原型指向父类对象 | 是 | 是 | 否 | 是 | 简单实现对象继承 | 共享引用类型属性,无法识别构造函数 |
寄生式继承 | 在原型式基础上增强子类对象 | 是 | 是 | 否 | 是 | 能增强子类功能 | 无法继承父类构造函数的私有属性 |
ES6类继承 | 使用 class和 extends关键字 | 是 | 是 | 是 | 否 | 语法简洁,支持 super | 需要ES6环境支持,语法糖 |
总结
JavaScript提供了多种继承方式,每种方法都有其独特的优点和适用场景。原型链继承适合简单的继承需求,但存在属性共享问题;构造函数继承能够解决属性共享问题,但无法继承父类的方法;组合继承兼具两者优点,是较为常用的继承方式;原型式继承和寄生式继承适合特定场景下的对象创建;而ES6类继承则以其简洁的语法和强大的功能,成为现代JavaScript开发中推荐的继承方式。
在实际开发中,应根据具体需求和项目环境,选择最合适的继承方法,以实现代码的高效复用和维护。
通过本文的详细解析,相信你已经对JavaScript中各种继承方法有了深入的理解。在选择继承方式时,请根据项目需求和实际场景,灵活运用,编写出高效、可维护的代码。
相关推荐
- 自学Python,写一个挨打的游戏代码来初识While循环
-
自学Python的第11天。旋转~跳跃~,我~闭着眼!学完循环,沐浴着while的光芒,闲来无事和同事一起扯皮,我说:“编程语言好神奇,一个小小的循环,竟然在生活中也可以找到原理和例子”,同事也...
- 常用的 Python 工具与资源,你知道几个?
-
最近几年你会发现,越来越多的人开始学习Python,工欲善其事必先利其器,今天纬软小编就跟大家分享一些常用的Python工具与资源,记得收藏哦!不然下次就找不到我了。1、PycharmPychar...
- 一张思维导图概括Python的基本语法, 一周的学习成果都在里面了
-
一周总结不知不觉已经自学Python一周的时间了,这一周,从认识Python到安装Python,再到基本语法和基本数据类型,对于小白的我来说无比艰辛的,充满坎坷。最主要的是每天学习时间有限。只...
- 三日速成python?打工人,小心钱包,别当韭菜
-
随着人工智能的热度越来越高,许多非计算机专业的同学们也都纷纷投入到学习编程的道路上来。而Python,作为一种相对比较容易上手的语言,也越来越受欢迎。网络上各类网课层出不穷,各式广告令人眼花缭乱。某些...
- Python自动化软件测试怎么学?路线和方法都在这里了
-
Python自动化测试是指使用Python编程语言和相关工具,对软件系统进行自动化测试的过程。学习Python自动化测试需要掌握以下技术:Python编程语言:学习Python自动化测试需要先掌握Py...
- Python从放弃到入门:公众号历史文章爬取为例谈快速学习技能
-
这篇文章不谈江流所专研的营销与运营,而聊一聊技能学习之路,聊一聊Python这门最简单的编程语言该如何学习,我完成的第一个Python项目,将任意公众号的所有历史文章导出成PDF电子书。或许我这个Py...
- 【黑客必会】python学习计划
-
阅读Python文档从Python官方网站上下载并阅读Python最新版本的文档(中文版),这是学习Python的最好方式。对于每个新概念和想法,请尝试运行一些代码片段,并检查生成的输出。这将帮助您更...
- 公布了!2025CDA考试安排
-
CDA数据分析师报考流程数据分析师是指在不同行业中专门从事行业数据搜集、整理、分析依据数据作出行业研究评估的专业人员CDA证书分为1-3级,中英文双证就业面广,含金量高!!?报考条件:满18...
- 一文搞懂全排列、组合、子集问题(经典回溯递归)
-
原创公众号:【bigsai】头条号:程序员bigsai前言Hello,大家好,我是bigsai,longtimenosee!在刷题和面试过程中,我们经常遇到一些排列组合类的问题,而全排列、组合...
- 「西法带你学算法」一次搞定前缀和
-
我花了几天时间,从力扣中精选了五道相同思想的题目,来帮助大家解套,如果觉得文章对你有用,记得点赞分享,让我看到你的认可,有动力继续做下去。467.环绕字符串中唯一的子字符串[1](中等)795.区...
- 平均数的5种方法,你用过几种方法?
-
平均数,看似很简单的东西,其实里面包含着很多学问。今天,分享5种经常会用到的平均数方法。1.算术平均法用到最多的莫过于算术平均法,考试平均分、平均工资等等,都是用到这个。=AVERAGE(B2:B11...
- 【干货收藏】如何最简单、通俗地理解决策树分类算法?
-
决策树(Decisiontree)是基于已知各种情况(特征取值)的基础上,通过构建树型决策结构来进行分析的一种方式,是常用的有监督的分类算法。决策树算法是机器学习中的一种经典算法,它通过一系列的规则...
- 面试必备:回溯算法详解
-
我们刷leetcode的时候,经常会遇到回溯算法类型题目。回溯算法是五大基本算法之一,一般大厂也喜欢问。今天跟大家一起来学习回溯算法的套路,文章如果有不正确的地方,欢迎大家指出哈,感谢感谢~什么是回溯...
- 「机器学习」决策树——ID3、C4.5、CART(非常详细)
-
决策树是一个非常常见并且优秀的机器学习算法,它易于理解、可解释性强,其可作为分类算法,也可用于回归模型。本文将分三篇介绍决策树,第一篇介绍基本树(包括ID3、C4.5、CART),第二篇介绍Ran...
- 大话AI算法: 决策树
-
所谓的决策树算法,通俗的说就是建立一个树形的结构,通过这个结构去一层一层的筛选判断问题是否好坏的算法。比如判断一个西瓜是否好瓜,有20条西瓜的样本提供给你,让你根据这20条(通过机器学习)建立起...
- 一周热门
- 最近发表
- 标签列表
-
- kubectlsetimage (56)
- mysqlinsertoverwrite (53)
- addcolumn (54)
- helmpackage (54)
- varchar最长多少 (61)
- 类型断言 (53)
- protoc安装 (56)
- jdk20安装教程 (60)
- rpm2cpio (52)
- 控制台打印 (63)
- 401unauthorized (51)
- vuexstore (68)
- druiddatasource (60)
- 企业微信开发文档 (51)
- rendertexture (51)
- speedphp (52)
- gitcommit-am (68)
- bashecho (64)
- str_to_date函数 (58)
- yum下载包及依赖到本地 (72)
- jstree中文api文档 (59)
- mvnw文件 (58)
- rancher安装 (63)
- nginx开机自启 (53)
- .netcore教程 (53)