JS继承与原型、原型链

embedded/2024/12/22 11:33:09/

在 JavaScript 中,继承是实现代码复用和构建对象关系的重要概念。本文将讨论原型链继承、构造函数继承以及组合继承等几种常见的继承方式,并提供相应的示例代码,并分析它们的特点、优缺点以及适用场景。

在开始讲解 JavaScript 的继承方式之前,我们先来详细解释一下原型(prototype)、构造函数(constructor)和实例对象(instance)这三个概念。因为只有对它们有清晰的理解,才能更好地理解和应用JavaScript的继承机制。现在我们将分别介绍它们的含义和它们之间的关系。

建议点赞收藏本文章,以便日后复习~~

原型、构造函数、实例对象

image.png

在 JavaScript 中,原型(prototype)、构造函数(constructor)和实例对象(instance)是面向对象编程中的重要概念,并且它们之间存在着紧密的关系。

  1. 原型(prototype): 原型是JavaScript中对象之间关联的一种机制。每个JavaScript对象(除了 null 和 undefined)都有一个原型对象,它包含了对象的属性和方法。当我们访问一个对象的属性或方法时,如果对象本身没有定义该属性或方法,JavaScript引擎会通过原型链向上查找,直到找到对应的属性或方法为止。同理,原型链是由对象的原型对象构成的链式结构,通过这种机制,对象可以继承原型对象的属性和方法。
  2. 构造函数(constructor): 构造函数是用于创建对象的函数。在JavaScript中,我们可以通过定义一个函数并使用 new 关键字来创建对象的实例。构造函数定义了对象的初始状态和行为,并且可以在创建实例时对其进行初始化。构造函数可以包含属性和方法,并且可以使用 this 关键字引用要创建的实例对象。
  3. 实例对象(instance): 实例对象是通过构造函数创建的对象,它具有构造函数定义的属性和方法。每个实例对象都是独立的,它们可以根据需要修改自己的属性值,并且可以调用构造函数中定义的方法。实例对象通过原型链与构造函数的原型对象关联在一起,从而实现属性和方法的继承。
function Animal(name) {  // 构造函数(自带原型对象)this.name = name || 'Animal'; // 属性
}Animal.prototype.eat = function(food) { // 方法console.log(this.name + '正在吃:' + food);
};var animal = new Animal('Tom'); // 实例对象animal.eat('猫粮')

它们之间的关系如下:

  • 每个构造函数都有一个原型对象(prototype),构造函数的原型对象包含了构造函数定义的属性方法
  • 通过构造函数创建的每个实例对象都有一个内部属性(Prototype),它指向构造函数的原型对象。这个属性在浏览器中通常可以通过 __proto__ 访问(某些浏览器不支持)。
  • 实例对象可以访问构造函数原型对象中的属性和方法。因为它们通过原型链与原型对象关联在一起,如果实例对象访问的属性或方法在自身中找不到,JavaScript引擎会自动沿着原型链向上查找,直到找到对应的属性或方法
  • 当我们修改实例对象的属性时,它会在自身中创建一个与原型对象中同名属性的副本,并在之后的访问中直接使用该副本,而不会影响原型对象中的属性
  • 当我们调用实例对象的方法时,JavaScript引擎会优先在实例对象中查找对应的方法,如果找不到则会继续沿着原型链向上查找,直到找到对应的方法。

什么是JavaScript继承

JavaScript继承是指在前端开发中,使用JavaScript实现对象之间属性和方法的继承关系。继承是面向对象编程的重要概念,它允许我们创建基于现有对象的新对象,并在新对象中拥有原有对象的属性和方法

在JavaScript中,继承是通过原型链来实现的。每个对象都有一个原型对象,它包含对象的属性和方法。当我们访问一个对象的属性或方法时,如果对象本身没有定义该属性或方法,JavaScript引擎会通过原型链向上查找,直到找到对应的属性或方法为止。这种原型链的查找机制使得对象之间可以共享属性和方法,从而实现继承的效果。

原型与对象的关系.jpeg

除了原型链继承外,JavaScript还提供了其他几种实现继承的方式,如构造函数继承、组合继承等。在开发中,继承通常用于构建对象之间的关系,使得子类可以共享父类的属性和方法,并有能力添加自己的特定属性和方法。这样可以减少重复的代码编写,提高开发效率和代码的可维护性。

接下来我们详细介绍这些继承方式的原理和使用方法,并提供相应的代码示例。

JavaScript继承方式

1、原型链继承

原型链继承是一种基于原型的继承方式,它通过将父类的实例作为子类的原型来实现继承关系。具体实现如下:

javascript">function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat() {Animal.call(this);
}Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
Cat.prototype.name = 'Tom';var cat = new Cat();

原型链继承的特点包括:

  • 实例既是子类的实例,也是父类的实例,继承关系非常纯粹。
  • 子类可以访问父类新增的原型方法和属性。
  • 实现简单,易于理解和实现。

原型链继承的缺点:

  • 子类无法在构造器中新增属性和方法,只能在实例化后添加。
  • 无法实现多继承。
  • 所有实例共享来自原型对象的属性,包括引用属性。

原型链继承适用于简单的继承关系和单一继承需求的场景。

2、构造继承

构造继承通过在子类构造函数中调用父类构造函数,复制父类的实例属性给子类。具体实现如下:

javascript">function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {Animal.call(this, name);
}var cat = new Cat();

构造继承的特点包括:

  • 解决了原型链继承中子类实例共享父类引用属性的问题。
  • 可以在创建子类实例时向父类传递参数。
  • 支持多继承,可以调用多个父类构造函数。

构造继承的缺点:

  • 子类实例并不是父类的实例,只是子类的实例。
  • 无法继承父类的原型属性和方法。
  • 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能。

构造继承适用于需要继承实例属性、避免引用属性共享以及多继承的场景。

3、实例继承

实例继承通过为父类实例添加新特性,并将其作为子类实例返回。具体实现如下:

javascript">function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {var instance = new Animal();instance.name = name || 'Tom';return instance;
}var cat = new Cat();

实例继承的特点包括:

  • 不限制调用方式,无论是new 子类()还是子类(),返回的对象具有相同的效果。

实例继承的缺点:

  • 实例是父类的实例,而不是子类的实例。
  • 不支持多继承。

实例继承适用于灵活的对象创建需求,可以根据不同情况返回不同的实例。

4、拷贝继承

拷贝继承通过复制父类的属性和方法给子类实现继承。具体实现如下:

javascript">function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {Animal.call(this, name);
}for (var p in Animal.prototype) {if (Animal.prototype.hasOwnProperty(p)) {Cat.prototype[p] = Animal.prototype[p];}
}Cat.prototype.constructor = Cat;
var cat = new Cat();

拷贝继承的特点包括:

  • 支持多继承。

拷贝继承的缺点:

  • 效率较低,内存占用高,因为需要拷贝父类的属性。
  • 无法获取父类的不可枚举方法。

拷贝继承适用于多继承的场景,但要注意性能和不可枚举方法的问题。

5、组合继承(原型继承+构造继承)

组合继承结合了原型继承和构造继承的优点,通过调用父类构造函数来继承父类的属性,并将父类实例作为子类原型,实现函数复用。具体实现如下:

javascript">function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {Animal.call(this, name);
}Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;var cat = new Cat();

组合继承的特点包括:

  • 继承父类实例属性和方法。
  • 继承父类原型属性和方法。
  • 既是父类的实例,也是子类的实例。

组合继承的缺点:

  • 调用了两次父类构造函数,影响性能。

组合继承适用于大多数场景,是一种常用的继承方式。

6、寄生组合继承

寄生组合继承是对组合继承的优化,通过寄生方式避免了两次调用父类构造函数,从而减少了实例化时的重复操作。具体实现如下:

javascript">function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {Animal.call(this, name);
}function inheritPrototype(subType, superType) {var prototype = Object.create(superType.prototype);prototype.constructor = subType;subType.prototype = prototype;
}inheritPrototype(Cat, Animal);var cat = new Cat();

寄生组合继承的特点包括:

  • 实现简单,堪称完美。

寄生组合继承没有明显的缺点,是一种高效且可靠的继承方式。

结语

我们可以根据具体需求选择适合的继承方式。每种继承方式都有自己的优缺点和适用场景,因此我们应根据实际情况进行选择和灵活运用。


http://www.ppmy.cn/embedded/6459.html

相关文章

什么是边缘计算?它为何如此重要?-天拓四方

随着信息技术的快速发展,数据处理和计算的需求日益增大,特别是在实时性要求极高的场景中,传统的云计算模式面临着巨大的挑战。在这样的背景下,边缘计算作为一种新兴的计算模式,正逐渐受到业界的广泛关注。那么&#xf…

单页面应用使用Nginx部署页面路由直接访问404问题

使用Nginx发布单页面应用时候,因为只有一个index.html页面可能导致直接访问具体页面路由报404错误,如: 直接访问http://www.test.com正常 访问http://www/test.com/system/list 则报404 需要修改nginx配置让其所有未找到资源都返回到index.h…

免费使用ChatGPT 4.0 和 文心一言 4.0

前言 今天给大家分享如何免费使用ChatGPT4.0 和 文心一言 4.0,废话就不多说了,我们直接入正题。 ChatGPT 4.0 先来看看如何免费使用ChatGPT 4.0 进入Coze登录 https://www.coze.com 选择大圣-GPT-4 文心一言 4.0 通过文心智能体平台,就…

Node.js环境WebSocket示例

server.js: const WebSocket require(ws);const wss new WebSocket.Server({ port: 3000 });wss.on(connection, function connection(ws) {console.log(客户端已连接);ws.on(message, function incoming(message) {console.log(收到客户端消息:, message);ws.se…

【论文速读】| 大语言模型是边缘情况模糊测试器:通过FuzzGPT测试深度学习库

本次分享论文为:Large Language Models are Edge-Case Fuzzers: Testing Deep Learning Libraries via FuzzGPT 基本信息 原文作者:Yinlin Deng, Chunqiu Steven Xia, Chenyuan Yang, Shizhuo Dylan Zhang, Shujing Yang, Lingming Zhang 作者单位&…

python免费调用阿里云通义千问(q-wen-max)大模型API

文章目录 通义千问开通免费API Keypython调用阿里云通义千问API 通义千问 通义千问,是基于阿里巴巴达摩院在自然语言处理领域的研究和积累。采用更先进的算法和更优化的模型结构,能够更准确地理解和生成自然语言、代码、表格等文本。 支持更多定制化需…

uni-app学习记录

uni-app 基础 uni-app环境搭建 命令行搭建 基础使用差异说明 要使用滚动 <scroll-view scroll-y"true" class"h-600">类似于v-html <rich-text nodes"<h1>1123213</h1>" /> <editor /> - text-area生命周期…

Django中如何实现防御CSRF攻击呢

在Django框架中&#xff0c;防御CSRF攻击已经被内置并默认启用。Django使用CSRF tokens来防止CSRF攻击&#xff0c;以下是Django实现防御CSRF攻击的基本步骤&#xff1a; 1. 中间件 确保django.middleware.csrf.CsrfViewMiddleware在你的MIDDLEWARE配置中启用。这个中间件负责…