JavaScript-继承
继承方式一
- 儿子继承父亲的物品就是继承最好的体现
- JS 中的继承的目的,把子类型中共同的属性和方法提取到父类型中
- 减少代码的冗余度,提升代码的复用性
废话不多说直接上代码,如下有一个构造函数当中有两个属性和一个方法,有了构造函数之后就可以创建对象在使用创建好的对象访问属性与方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<script type="text/javascript">
function Person() {
this.name = null;
this.age = 0;
this.say = function () {
console.log(this.name, this.age);
}
}
let person = new Person();
person.name = "BNTang";
person.age = 34;
person.say();
</script>
</head>
<body>
</body>
</html>
看了如上的代码之后接下来我又定义了一个构造函数,也有姓名年龄,但是除了这些属性之外该构造函数还有新的属性和方法如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<script type="text/javascript">
function Person() {
this.name = null;
this.age = 0;
this.say = function () {
console.log(this.name, this.age);
}
}
let person = new Person();
person.name = "BNTang";
person.age = 34;
person.say();
function Student() {
this.name = null;
this.age = 0;
this.say = function () {
console.log(this.name, this.age);
}
this.score = 0;
this.study = function () {
console.log("day day up");
}
}
let student = new Student();
student.name = "zs";
student.age = 18;
student.score = 99;
student.say();
student.study();
</script>
</head>
<body>
</body>
</html>
经过如上两波代码之后发现冗余代码太多了,这个时候有没有什么方案可以优化一下如上的代码来减少一些冗余代码呢?当然是有的,在企业开发中如果构造函数和构造函数之间的关系是 is a
关系,那么就可以使用继承来优化代码,来减少代码的冗余度,使用继承改造之后的代码如下,更改了 Student 原型对象 为 Perosn 在参考 JavaScript-原型链 的介绍即可了解具体过程,为了不破坏原有的关系, 在给 prototype 赋值的时候,需要在自定义的对象中手动的添加 constructor 属性, 手动的指定需要指向谁
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<script type="text/javascript">
function Person() {
this.name = null;
this.age = 0;
this.say = function () {
console.log(this.name, this.age);
}
}
let person = new Person();
person.name = "BNTang";
person.age = 34;
person.say();
function Student() {
this.score = 0;
this.study = function () {
console.log("day day up");
}
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
let student = new Student();
student.name = "zs";
student.age = 18;
student.score = 99;
student.say();
student.study();
</script>
</head>
<body>
</body>
</html>
继承方式一弊端
过去我们想要在创建对象的时候就给对象属性指定对应的值,只需要将构造函数添加了对应的形参然后在创建的时候给入对应的形参即可代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript-继承方式一弊端</title>
<script>
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name, this.age);
}
}
let person = new Person("BNTang", 34);
person.say();
function Student(name, age, score) {
this.score = score;
this.study = function () {
console.log("day day up");
}
}
let student = new Student("BNTang", 23, 100);
student.name = "zs";
student.age = 18;
student.score = 99;
student.say();
student.study();
Student.prototype = new Person();
Student.prototype.constructor = Student;
</script>
</head>
<body>
</body>
</html>
但是通过这种方式就引出了第一种继承方式的弊端了
出现该弊端的原因也很简单,必须当执行了如下的代码之后 Student 才可以找到对应的属性 name 与 age,所以没有办法在创建 Student 的时候就给 name 与 age 同时赋值的,所以我将介绍第二种继承的方式来完善一下这个弊端,要想使用第二种继承方式首先还需要了解 JavaScript-bind-call-apply 知识点
Student.prototype = new Person();
继承方式二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript-继承方式二</title>
<script>
function Person(name, age) {
// this = Student
// Student.name
// Student.age
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name, this.age);
}
}
function Student(name, age, score) {
// this = Student
Person.call(this, name, age)
this.score = score;
this.study = function () {
console.log("day day up");
}
}
let student = new Student("BNTang", 23, 100);
student.name = "zs";
student.age = 18;
student.score = 99;
student.say();
student.study();
let person = new Person("Jonathan_Lee", 34);
person.say();
</script>
</head>
<body>
</body>
</html>
如果你对如上的代码不够清晰你可以回去看看构造函数的创建过程,内部会自动的进行创建一个对象赋值给 this 变量然后返回 this 可参考 JavaScript-构造函数,利用了 call 改变了 Person 的 this 所以就是 Student.name,Student.age
继承方式二弊端
如果我将 Person 构造函数中的 say 删除添加到 Person 的原型对象当中这样 Student 就不会动态的进行添加 say 方法就会出现问题改造了的代码如下所示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript-继承方式二弊端</title>
<script>
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
function Student(name, age, score) {
Person.call(this, name, age)
this.score = score;
this.study = function () {
console.log("day day up");
}
}
let student = new Student("BNTang", 23, 100);
student.name = "zs";
student.age = 18;
student.score = 99;
student.say();
student.study();
let person = new Person("Jonathan_Lee", 34);
person.say();
</script>
</head>
<body>
</body>
</html>
继承方式二弊端在原型链与三角恋关系图如上,要想解决继承方式二的弊端就可以利用继承的第三种方式来解决
继承方式三
注意点:要想使用 Person 原型对象中的属性和方法,那么就必须将 Student 的原型对象改为 Person 的原型对象才可以改造了的代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript-继承方式三</title>
<script>
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
function Student(name, age, score) {
Person.call(this, name, age)
this.score = score;
this.study = function () {
console.log("day day up");
}
}
Student.prototype = Person.prototype;
Student.prototype.constructor = Student;
let student = new Student("BNTang", 23, 100);
student.name = "zs";
student.age = 18;
student.score = 99;
student.say();
student.study();
let person = new Person("Jonathan_Lee", 34);
person.say();
</script>
</head>
<body>
</body>
</html>
继承方式三弊端
由于修改了 Person 原型对象的 constructor
属性,所以破坏了 Person 的三角恋关系
由于 Person 和 Student 的原型对象是同一个,所以给 Student 的元素添加方法,Person 也会新增方法,造成了原型对象的污染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript-继承方式三弊端</title>
<script>
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
function Student(name, age, score) {
Person.call(this, name, age)
this.score = score;
this.study = function () {
console.log("day day up");
}
}
Student.prototype = Person.prototype;
Student.prototype.constructor = Student;
Student.prototype.run = function () {
console.log("run");
}
let person = new Person("Jonathan_Lee", 34);
person.run();
</script>
</head>
<body>
</body>
</html>
看了继承方式三的弊端之后,在来看看 JS 中继承的终极方法,在子类的构造函数中通过 call
借助父类的构造函数,将子类的原型对象修改为父类的实例对象即可
继承方式四
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript-继承方式四</title>
<script>
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
function Student(name, age, score) {
Person.call(this, name, age)
this.score = score;
this.study = function () {
console.log("day day up");
}
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
Student.prototype.run = function () {
console.log("run");
}
let student = new Student("BNTang", 23, 100);
student.name = "zs";
student.age = 18;
student.score = 99;
student.say();
student.study();
let person = new Person("Jonathan_Lee", 34);
person.say();
</script>
</head>
<body>
</body>
</html>
采用了继承方式四之后及解决了原型对象的污染问题,也解决了继承问题,首先去父类的构造函数找对应的属性和函数,没有的话又会去父类的实例找,实例没有会去实例对应的原型对象中找🐤
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具