JavaScript的原型链

news2024/12/22 20:44:50

JavaScript的原型链

JavaScript的继承主要是通过原型链实现的,所以理解原型链是掌握JavaScript继承的关键一环。原型链的继承的基本思想是通过原型链继承多个引用类型的属性和方法。

理解原型链

关于原型链的定义与理解:

每个构造函数都有一个原型对象,原型有一个属性指向构造函数,而实例有一个内部指针指向原型。但是如果原型是另外一个类型的实例呢,那么就意味着这个原型本身有一个内部指针指向另外一个原型,相应地另外一个原型也有一个指针指向另一个构造函数。这样实例和原型之间构造了一条原型链。这就是原型链的基本思想构成。

阅读下面的代码,来深入理解原型链:

function SuperType () {
    this.property = true;
}

SuperType.prototype.getSuperValue = function () {
    return this.property;
}

function SubType() {
    this.subproperty = false;
}

// 现在让之类继承父类SuperType

SubType.prototype = new SuperType()

SubType.prototype.getSubValue = function() {
    return this.subproperty;
};

const instance = new SubType();

console.log(instance.getSuperValue());

上面代码定义了两个类:父类SuperType和子类SubType,并且分别定义了一个属性和方法。其中SubType是通过创建SuperType的实例并将其赋值给自己的原型(SubType.prototype)实现了对SuperType的继承。这个赋值重写了SubType最初的原型,并将其替换为SuperType的实例。这就意味着SuperType实例可以访问的属性和方法也会存在于SubType.prototype

在这里插入图片描述

这个例子中实现继承的关键,是SubType没有使用默认原型,而是将其替换成了一个新的对象。这个新的对象恰好是SuperType的实例。这样一来,SubType的实例不仅能从SuperType的实例中继承属性和方法,而且还与SuperType的原型挂上了钩。于是instance(通过内部的[[Prototype]])指向SubType.prototype,而SubType.prototype(作为SuperType的实例又通过内部的[[Prototype]])指向SuperType.prototype。注意,getSuperValue()方法还在SuperType.prototype对象上,而property属性则在SubType.prototype上。这是因为getSuperValue()是一个原型方法,而property是一个实例属性。SubType.prototype现在是SuperType的一个实例,因此property才会存储在它上面。还要注意,由于SubType.prototypeconstructor属性被重写为指向SuperType,所以instance.constructor也指向SuperType.

默认情况下,所有引用类型都继承自Object,这也是通过原型链实现的。任何函数的默认原型都是一个Object的实例,这意味着这个实例有一个内部指针指向Object.prototype。这也是为什么自定义类型能够继承包括toString()valueOf()在内的所有默认方法的原因。SubType继承SuperType,而SuperType继承Object。在调用instance.toString()时,实际上调用的是保存在Object.prototype上的方法。

我们知道,在读取实例上的属性时,首先会在实例上搜索这个属性。如果没找到,则会继承搜索实例的原型。在通过原型链实现继承之后,搜索就可以继承向上,搜索原型的原型。对前面的例子而言,调用instance.getSuperValue()经过了3步搜索:instanceSubType.prototypeSuperType.prototype,最后一步才找到这个方法。对属性和方法的搜索会一直持续到原型链的末端。这就是原型链的向上搜索功能。

原型链与继承

原型与实例的关系可以通过两种方式来确定:instanceofisPrototypeOf

instanceof操作符

使用instanceof操作符,如果一个实例的原型链中出现过相应的构造函数,则instanceof返回true。示例如下:

console.log(instance instanceof Object); // true
console.log(instance instanceof SuperType); // true
console.log(instance instanceof SubType); // true 

因为instanceObjectSuperTypeSubType,所以使用instanceof操作符返回true

isPrototypeOf方法

使用isPrototypeOf()方法。原型链中的每个原型都可以调用这个方法,如下例所示,只要原型链中包含这个原型,这个方法就返回true

console.log(Object.prototype.isPrototypeOf(instance)); // true
console.log(SuperType.prototype.isPrototypeOf(instance)); // true
console.log(SubType.prototype.isPrototypeOf(instance)); // true 

原型链继承所面临的问题

新增或重新方法的要点

子类可以增加新的方法或者覆盖父类的方法

// 覆盖父类的方法
SubType.prototype.getSuperValue = function() {
  return false;
};

需要注意的是,我们应该避免使用以对象字面量方式创建原型方法,在会破坏之前的原型链,因为这相当于重写
了原型链。

function SuperType () {
  this.property = true;
}

SuperType.prototype.getSuperValue = function () {
  return this.property;
}

function SubType() {
  this.subproperty = false;
}

// 现在让之类继承父类SuperType

SubType.prototype = new SuperType()

SubType.prototype = {
  getSubValue() {
    return this.subproperty;
  },
  getOtherMethod() {
    return false;
  }
}

在这段代码中,子类的原型在被赋值为SuperType的实例后,又被一个对象字面量覆盖了。覆盖后的原型是一个Object的实例,而不再是SuperType的实例。因此之前的原型链就断了。SubTypeSuperType之间也没有关系了。

原型链继承的引用问题

原型链虽然是实现继承的强大工具,但它也有问题。主要问题出现在原型中包含引用值的时候。前面在谈到原型的问题时也提到过,原型中包含的引用值会在所有实例间共享,这也是为什么属性通常会在构造函数中定义而不会定义在原型上的原因。在使用原型实现继承时,原型实际上变成了另一个类型的实例。这意味着原先的实例属性摇身一变成为了原型属性。

function SuperType() {
 this.colors = ["red", "blue", "green"];
}
function SubType() {}
// 继承 SuperType
SubType.prototype = new SuperType();

let instance1 = new SubType();

instance1.colors.push("black");

console.log(instance1.colors); // "red,blue,green,black"

// 因为colors是因为类型,上一个实例instance1修改了属性,进而影响了第二个实例
let instance2 = new SubType();
console.log(instance2.colors); // "red,blue,green,black" 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/115916.html

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

相关文章

Python实现将位图描摹为彩色矢量 svg 图片的源代码,Python实现位图转彩色矢量代码

Color Trace 这是一个将位图描摹为彩色矢量 svg 图片的程序,是一个命令行工具,使用 Python 脚本实现,运行环境 Python3.8。 ✨ 效果 以一个字帖图片为例,这是 png 格式的位图(370KB): 这是颜…

多智能体强化学习环境【星际争霸II】SMAC环境配置

多智能体强化学习这个领域中,很多Paper都使用的一个环境是——星际争多智能体挑战(StarCraft Multi-Agent Challenge, SMAC)。最近也配置了这个环境,把中间一些步骤记录下来。2022.12.26 文章目录1 环境介绍1.1 相关论文1.2 项目代码地址2 安装过程3 相关…

2023年pmp的考试时间是什么时候?(含pmp资料)

不出意外,按照原计划,就是3、6、9、12月,22年11月延期考试地区的考生或者退考的估计会在3月或者6月考。具体就及时关注官网消息。 ​新版中文报名网站:中国国际人才交流基金会 这里说一下PMP的基本考试情况: 【考试注…

模型实战(2)之YOLOv5 实时实例分割+训练自己数据集

模型实战(2)之YOLOv5 实时实例分割训练自己数据集 本文将详解YOLOv5实例分割模型的使用及从头训练自己的数据集得到最优权重,可以直接替换数据集进行训练的训练模型可通过我的gitcode进行下载:https://gitcode.net/openmodel/yolo…

使用matplotlib画图 + python色彩大全

目录画线画点散点画点的形状、线的形状画点线在特定位置写文字plt.legend()中图例的位置方法一 plt.legend(loc4)方法二 plt.legend(bbox_to_anchor(num1, num2))方法三 bbox_to_anchor(1.05, 1), loc2, borderaxespad0保存图片指定图片大小网格线根据自己的需求做了一个画图的…

图的最短路径

文章目录单源最短路径-Dijkstra算法单源最短路径--Bellman-Ford算法多源最短路径--Floyd-Warshall算法单源最短路径-Dijkstra算法 针对一个带权有向图G,将所有结点分为两组S和Q,S是已经确定最短路径的结点集合,在初始时为空(初始…

如何使用监控诊断工具Arthas(阿尔萨斯)

Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信…

【python】实现精美圣诞树-拿下女神不是梦

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 🏅阿里云ACE认证高级工程师 🏅阿里云开发者社区专…

Java Web基础面试题

✅作者简介:热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏:Java面试题…

【K3s】第4篇 一篇文章带你了解使用Kompose

目录 1、Kompose介绍 2、安装Kompose 3、docker-compose文件转换为k8s文件 1、Kompose介绍 kompose是一个帮助熟悉 Kubernetes 的用户迁移到k8s的工具。 获取 Docker Compose 文件并将其转换为 Kubernetes 资源。 kompose是一个方便的工具,可以从本地 Docker …

Ffuf爆破神器(超详细)

目录为什么是Ffuf基本使用最基本的使用多个字典同时使用带cookie扫描(-b)静默模式(-s)递归扫描(-recursion)指定扩展名(-e)POST请求爆破方式1:指明请求地址和请求体【不推…

iOS 自动化测试踩坑(一): 技术方案、环境配置与落地实践

移动端的自动化测试,最常见的是 Android 自动化测试,我个人觉得 Android 的测试优先级会更高,也更开放,更容易测试;而 iOS 相较于 Android 要安全稳定的多,但也是一个必须测试的方向,这个系列文…

Android实现雪花特效自定义view

一、前言 这个冬天,老家一直没有下雨, 正好圣诞节,就想着制作一个下雪的特效。 圣诞祝福:平安夜,舞翩阡。雪花飘,飞满天。心与心,永相伴。 圣诞节是传统的宗教节日,对于基 督徒&…

前端自学你还在浪费时间吗?

其实最主要不是学的过程,而是学完后,你有没有把今天的练习题自己在重新敲个2,3遍,这样印象就会更加深刻,以后自己写代码的时候也会更加的得心应手。 手抄笔记让我打好了HTML基础和良好的CSS能力,当然这不一…

Cesium打包入门(gulp与esbuild)

本文针对Cesium源码包的打包工具gulp和esbuild进行了初步探讨,属于入门篇。 首先简要介绍采用gulpesbuild如何为多个源代码文件打包成一个单独文件,然后介绍了下Cesium中的源码包的结构,并简要分析了其打包的相关函数。 本文编译环境IDE使用…

【并发编程学习】一、线程的基本认识

一、线程的基本认识 1.1线程的基本介绍 线程是什么? 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运行单位。 为什么会有多线程? ①因为其是CPU的最小调度单位,所以在多核CPU中&#xff0c…

圣诞节,深圳街头有点冷清了~

正文大家好,我是bug菌~今天是圣诞节,这也是我新冠康复的第二周了吧,还有点小咳嗽,伴随有点鼻炎,不过这周已经上了三天班了,整体感觉还算好吧,毕竟我嘴巴不硬,也比较低调不嚣张&#…

底层硬件创新夯实算力、应用创新贴近业务:英特尔至强助力下的VR医疗培训系统

早在1935年,科幻小说家斯坦利温鲍姆的小说《皮格马利翁的眼镜》中,就构想了一款实现虚拟现实(VR)的眼镜。近年来,除游戏、娱乐等大众熟知的应用场景外,VR逐渐涉足医疗、教育、生产制造等各种领域。 以医疗…

LeetCode-1759-统计同构子字符串的数目

1、数学 我们可以使用数学进行分析:每当出现连续的nnn个字符时,我们最终将其合在一起进行计算个数。显然我们可以获得的同构子字符串的个数应为n(n1)2\frac{n \times (n1)}{2}2n(n1)​。因此我们只需要遍历整个字符串,分别统计连续出现的字符…

57岛屿数量-61全排列 最长递增路径

57岛屿数量 矩阵中多处聚集着1,要想统计1聚集的堆数而不重复统计,那我们可以考虑每次找到一堆相邻的1,就将其全部改成0,而将所有相邻的1改成0的步骤又可以使用深度优先搜索(dfs):当我们遇到矩阵…