JS继承与原型、原型链

在 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、原型链继承

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

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、构造继承

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

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、实例继承

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

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、拷贝继承

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

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、组合继承(原型继承+构造继承)

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

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、寄生组合继承

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

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.mzph.cn/news/794005.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于javassmJSP的家用电器销售网站

开发语言:Java 框架:ssm 技术:JSP JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclip…

软件质量保证计划书

1 概述 2 质量目标 3 项目基本情况 4 资源 4.1 人员 4.1.1 组织结构 4.1.2 职责 4.2 工具及设施 5 质量保证的主要工作 6 质量保证工作量估算 7 质量保证工作提交的产物 8 变更管理 9 评价标准 10 形成的记录 软件全资料获取进主页或者本文末个人名片直接获取。

Spring/SpringBoot/SpringCloud Mybatis 执行流程

在后续分析Mybatis 流程中代码的可能会用到IDEA debug 技巧: 条件断点 代码断点,右键 勾选弹窗 Condition : 写入表达式 回到上一步: Java动态代理实现 InvocationHandler接口: package com.lvyuanj.core.test;…

Unity:2D SpriteShape

1.1 简介 Sprite Shape 可以很灵活的更改sprite的轮廓。比如: 它由两部分组成:Sprite Shape Profile、Sprite Shape Controller,需要导入2D Sprite Shape Package. 1.1.1 Sprite导入要求 Texture Type - ‘Sprite (2D and UI)’.Sprite Mo…

备战蓝桥杯---刷二分与前缀和题

刷点题~ 1.二分多路归并算法 对于每一个技能,我们把它看成一个等差数列,我们把所有可能都放到一个集合里,排个序,取前m个大即可,现在考虑优化,假如m不是很大,我们直接用优先队列即可&#xff0…

python写文件怎么读出来

python中对文件的操作大概分为三步:打开文件、操作文件(读、写、追加写入)、关闭文件。 1、无论对文件做哪种操作,操作前首先要保证文件被打开了,即需要一个打开的操作。 例:open(XXX.txt) 打开文件的同…

python函数练习2

找出10000以内能被5或6整除,但不能被两者同时整除的数(函数) def func():for i in range(1,50):if (i % 5 0 or i % 6 0 ):if i % 5 0 and i % 6 0:continue #利用continue跳过能被5和6整除的数print(i) func()写一个方法,计算…

C#智慧手麻系统源码 医院手术麻醉系统源码 支持三甲医院评级需求 可提供演示

C#智慧手麻系统源码 医院手术麻醉系统源码 支持三甲医院评级需求 可提供演示 手术麻醉管理系统是应用于医院手术室、麻醉科室的计算机软件系统。该系统针对整个围术期,对病人进行全程跟踪与信息管理,自动集成病人HIS、LIS、RIS、PACS信息,采…

Autosar工具链配置 CanNM

CAN网络管理filter 网管报文范围0x600~0x6FF repeat message time 超时时间 接收到主动唤醒源,网管报文快发周期,次数;正常周期发送时间 网管报文btye设置:1、重复消息请求位设置 2、ECU地址 wait bus-sleep 定时设置以及网管报…

华为云1核2G免费使用一年

个人用户专享云服务器、云数据库产品每天上午9:30开抢,其他产品每天0点开放领取,企业用户所有产品每天0点开放领取; 云产品体验名额有限,领完即止。详情:https://www.vpspick.com/vps/591.html 通用入门型 T6 云服务…

2024免费Mac苹果解压压缩包软件BetterZip5

在2024年,对于Mac电脑用户来说,如果你想要无需解压就能快速查看压缩文档的内容,BetterZip是一个极佳的选择。这款软件不仅支持多种格式的压缩和解压,如zip、rar、7z、tar等,还具备丰富的功能和设置,包括预览…

QT-QPainter

QT-QPainter 1.QPainter画图  1.1 概述  1.1 QPainter设置  1.2 QPainter画线  1.3 QPainter画矩形  1.4 QPainter画圆  1.5 QPainter画圆弧  1.6 QPainter画扇形 2.QGradient  2.1 QLinearGradient线性渐变  2.2 QRadialGradient径向渐变  2.3 QConicalGr…

二、GitLab相关操作

GitLab相关操作 一、组、用户、项目管理1.创建组2.创建项目3.创建用户并分配组3.1 创建用户3.2 设置密码3.3 给用户分配组 二、拉取/推送代码1.配置ssh(第一次需要)1.1 创建一个空文件夹1.2 配置本地仓账号和邮箱1.3 生成ssh公钥密钥1.4 gitlab配置公钥 2.拉取代码3.推送代码3.…

C语言动态内存空间分配

1. 前言 在讲内存分配前,咱来聊一下为什么会有内存分配这个概念呢,大家都知道C语言当中是有着许多的数据类型,使用这些数据类型就会在内存上开辟其相对应的空间,那既然会开辟相应的空间,为什么还会有内存分配呢&#x…

springcloud基本使用三(搭建nacos)

window下安装nacos: 下载页面:Releases alibaba/nacos GitHuban easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. - Releases alibaba/nacoshttps://github.com/alibaba/nacos/releases…

基于卷积神经网络的中药识别(pytorch框架)【python源码+UI界面+前端界面+功能源码详解】

原作者链接:基于卷积神经网络的中药识别(pytorch框架)【python源码UI界面前端界面功能源码详解】_识别中药python-CSDN博客 //gitcode,gitee,飞桨,csdn,bilibili。几个有用网站,直接搜索即可,平…

主干网络篇 | YOLOv5/v7 更换骨干网络之 HGNetv2 | 百度新一代超强主干网络

本改进已融入到 YOLOv5-Magic 框架。 论文地址:https://arxiv.org/abs/2304.08069 代码地址:https://github.com/PaddlePaddle/PaddleDetection 中文翻译:https://blog.csdn.net/weixin_43694096/article/details/131353118 文章目录 HGNetv2网络结构1.1 主干网络1.2 颈部…

【Android】毫无耦合性,一个Item根布局搞定 item侧滑删除菜单,像IOS那样简单的使用侧滑删除。(1)

自定义ViewGroup实现侧滑删除简单,难得是还要同时 处理多指滑动的屏蔽,防止两个侧滑菜单同时出现,等等, 有办法将这些东西都用一个ViewGroup搞定么? 看本文如何巧用static类变量来解决这些矛盾冲突。 【2 预览】 那…

真快乐APP抢购源码实现

支持多个平台的自动 滑动验证码、选字验证码。缺点就是需要自己找一个验证码识别服务器,可以自己用python写一个,或者使用超级鹰(本篇教程就是使用它) 下面是实现源码 "ui"; Date.prototype.Format = function (fmt) {var o = {"M+": this.getMonth() …

2024年做抖音小店商家,最不该忽视的三个运营要点,一定要避开!

大家好,我是电商花花。 每一次平台规则的改变都深深的影响着我们无货源商家,我们只有在规则内行使,遵守规则,才能在安然无恙。 所以我们做抖音小店一定要及时关注平台的规则变化,以及整体的做店趋势。 只有这样才不…