简述 JavaScript 中 prototype
简述 JavaScript 中 prototype
这篇笔记主要捋一下这么几个概念:
- JS 的继承
- 构造函数
new的作用及简易实现__proto__&prototype- 同样的方法,class 和 prototype 中分别是怎么实现的
基础概念
JS 是通过 prototype chaining 实现继承的语言,所有的基类都会绑定在 prototype chain 上如:
class Base {constructor() {}
}class Extended extends Base {constructor() {super();}
}class Descendant extends Extended {constructor() {super();}
}const descedant = new Descendant();
console.log(descedant.__proto__);
__proto__ 本身就暴露了当前对象的 [[Prototype]],它所指向的是另一个对象,也就是 prototype chain 上的继承 (粗暴的理解一下就是父类)。返回的对象又可以通过调用 __proto__ 继续获得父类的 [[Prototype]],一步步向上追溯一直到 [[Prototype]] 为 null 为止,一般到这个时候,也是获取到 Object 了——JS 之中,除了 primitive type,万物皆对象。
需要注意的是,__proto__ 返回的对象是 [[Prototype]] 也是 <prototype>,二者是一样的,只不过前者是 chrome 的称呼,后者是 Firefox 的,这里为了一致就使用 [[Prototype]]。获取当前 [[Prototype]] 的方法有两种:
-
__proto__已经 Deprecated 了,deno 中甚至不支持实现
-
Object.getPrototypeOf()/Reflect.getPrototypeOf()推荐使用这个函数
构造函数
class 是 ES6 新出的语法糖,在 ES6 之前都是使用构造函数去实现的,如:
function Person(name, age) {this.name = name;this.age = age;
}// equivalent to
class Person {constructor(name, age) {this.name = name;this.age = age;}
}
实现结果都是一致的:

同样,constructor 也不是一定需要大写,小写也是可以实现同样的功能:
function person3(name, age) {this.name = name;this.age = age;
}const person3Instance = new person3('Deborah', 99);
console.log(person3Instance);

大写只是一个约定俗成的规范。
new 关键字
new 在使用构造函数的时候是必须的,否则它只是返回了一个 undefined:
function Person(name, age) {this.name = name;this.age = age;this.greet = function () {console.log('Hi there');};
}const person = Person('Tylor', 26);
console.log(person);
person.greet();

new 的作用在于
- 它创建了一个新的对象
- 它关联了对应的原型链继承
- 它绑定了
this的指向 - 它执行了构造函数内的部分
一个简单的实现 new 的函数为:
function myNew(constructorFn, ...args) {// 创建一个新的对象const obj = {};// 关联对应的原型链继承Object.setPrototypeOf(obj, constructorFn.prototype);// 执行了构造函数,同时使用 apply 也确定了 this 的指向const res = constructorFn.apply(obj, args);return typeof res === 'object' && res !== null ? res : obj;
}

__proto__ 和 prototype 的区别
简单的说就是,__proto__ 作用于实例上,而 prototype 作用于构造函数上。
如,准确的说函数的实现不是像上面那样实现的,而是:
Person.prototype.greet = function () {console.log(`Hi there, I am ${this.name},and I am ${this.age} years old`);
};
从自动提示上也可以看到,实例化的对象是无法访问内部的 [[Prototype]] 的:


另外,所有的函数实现其实都是绑定在 prototype 上的:

主要的原因就是因为函数本质上也是对象,而在每次实例化的时候都创建一个新的对象,是一个非常昂贵的事情。因此 JS 会将函数绑定到 [[Prototype]] 上,这样所有的实例化的对象可以共享一个函数。
如果想要每次实例化的时候都创建一个新的函数,则可以使用 arrow function(在 class 中使用),这也是 ES6 语法的 pro and con 了。
super 与 this
到这一步,基本上使用 prototype 去实现 class 都实现的差不多了,除了继承这一部分,以下面代码为例:
class Parent {constructor() {this.name = 'parent';}greet() {console.log(`This is ${this.name}`);}
}class Child extends Parent {constructor() {this.name = 'Child';}greet() {}
}const child = new Child();
事实上 JS 会报错:

在当调用了 super 之后就会发现,this 的指向被绑定到了 Child 中:
class Parent {constructor() {this.name = 'parent';}greet() {console.log(`This is ${this.name}`);}
}class Child extends Parent {constructor() {super();this.name = 'Child';}greet() {super.greet();}
}const child = new Child();
child.greet();

接下来要模拟实现的就是这一步,其中需要注意的就是:
-
实现继承关系
这点可以通过修改
prototype进行实现,已知[[Prototype]]中包含了所有的 prototype chain,这里也只需要将Child.prototype指向Parent.prototype,并且绑定对应的 构造函数即可。 -
修改
this的指向
function Parent() {this.name = 'Parent';
}Parent.prototype.greet = function () {console.log(`This is ${this.name}`);
};function Child() {// bind child to parentParent.call(this);this.name = 'Child';
}// set up inheritance
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;Child.prototype.greet = function () {Parent.prototype.greet.call(this);
};const child = new Child();
child.greet();

这样,prototype 中的继承关系也实现了。
这也是为什么 JS 推荐使用 class 而非重新实现一个 prototype 的原因,主要还是因为使用 class 的代码更加简洁易读。
相关文章:
简述 JavaScript 中 prototype
简述 JavaScript 中 prototype 这篇笔记主要捋一下这么几个概念: JS 的继承构造函数new 的作用及简易实现__proto__ & prototype同样的方法,class 和 prototype 中分别是怎么实现的 基础概念 JS 是通过 prototype chaining 实现继承的语言&#…...
一觉醒来Chat gpt就被淘汰了
目录 什么是Auto GPT? 与其他语言生成模型相比,Auto GPT具有以下优点 Auto GPT的能力 Auto GPT的能力非常强大,它可以应用于各种文本生成场景,包括但不限于以下几个方面 Auto GPT的历史 马斯克说:“ChatGPT 好得吓…...
13款JavaScript图像处理库,建议收藏备用
pica: 一个在浏览器中调整图像大小,而不会出现像素失真,处理速度非常快的图片处理库,仓库地址https://github.com/nodeca/picahtml2canvas: 强大的使用js开发的浏览器网页截图工具,仓库地址https://github.…...
uniapp m3u8格式视频加载
uniapp一:mui-player:三方 h5 web app uniapp 使用 mui-player 插件播放 m3u8/flv 视频流_翘翘红的博客-CSDN博客 uniapp 开发的h5项目,需要播放m3u8/flv后缀的视频,网上有很多视频插件,但是样式和效果不尽如人意&am…...
iOS描述文件(.mobileprovision)一键申请
iOS描述文件(.mobileprovision)一键申请 在主界面上点击描述文件按钮。 新建ios描述文件 然后点击新建,然后输入描述文件名称,描述文件名称字符和数字,自己好辨识就可以。然后选择描述文件类型,再选择bundle ID,如果…...
进行性能压力测试的原因、目的和好处
性能压力测试是指在模拟高负载、高并发情况下对软件系统进行测试,以衡量系统在实际使用过程中的性能表现。这些测试可以为生产环境中的应用程序提供关键数据,并帮助开发人员从根本上了解系统的实际性能。在本文中,我们将探讨进行性能压力测试…...
【计算机视觉】如何利用 CLIP 做简单的人脸任务?(含源代码)
文章目录 一、数据集介绍二、源代码 结果三、代码逐行解读 一、数据集介绍 CELEBA 数据集(CelebFaces Attributes Dataset)是一个大规模的人脸图像数据集,旨在用于训练和评估人脸相关的计算机视觉模型。该数据集由众多名人的脸部图像组成&a…...
基于显扬科技3D视觉相机的医疗试管分拣系统
行业现状: 医疗试管分拣是医疗行业中的一个重要环节,指将医疗实验室或生物技术研究中的试管按照一定的规则进行分拣,并对试管的类型、位置、数量等信息进行识别和管理。 随着医疗技术的不断发展和诊断治疗的精细化,医疗试管分拣…...
编译zlib
zlib被设计为一个免费的,通用的,法律上不受限制的-即不受任何专利保护的无损数据压缩库,几乎可以在任何计算机硬件和操作系统上使用。 官网:http://www.zlib.net/ 下载zlib源码:http://www.zlib.net/zlib1213.zip 备用地址&#x…...
如何让“ChatGPT自己写出好的Prompt的“脚本在这里
写个好的Prompt太费力了 在网上,你可能会看到很多人告诉你如何写Prompt,需要遵循各种规则,扮演不同的角色,任务明确、要求详细,还需要不断迭代优化。写一个出色的Prompt需要投入大量的时间和精力。甚至有一些公开的Pr…...
菜单选择shell
[rootes3 data]# vi action.sh #!/bin/bash . /etc/init.d/functionsecho -en "\E[$[RANDOM%731];1m"cat <<EOF请选择:1) 备份数据库2)清理日志3)软件升级4)软件回滚5)删库跑路EOFecho -en \E[0mread -p "请选择上面的项对应的数字1-5…...
Redis高可用性详解
目录 编辑 高可用性: 主从复制(Master-Slave Replication): 主从复制的一般工作流程: 哨兵模式(Sentinel Mode): 哨兵模式的一般工作流程: 集群模式(…...
MySQL(1) ---- 数据库介绍与MySQL概述
介绍 1、什么是数据库? 数据库:DateBase(DB),是存储和管理数据的仓库。数据库管理系统:DataBase Management System(DBMS),操纵和管理数据库的大型软件。SQL࿱…...
面试题之软件测试流程
说说公司的软件测试流程,这,是常考的面试题之一。 不同公司的流程不一样,现状决定流程,没有绝对的对错。 以结果为导向,保证产品质量,提高测试效率,才是王道。 以下的流程为业界比较标准的流程&…...
MyBatis中#{}与${}的区别,与各自的应用场景
#{}和${}的区别: #{}: 底层使用PreparedStatement。特点:先进行SQL语句的编译,然后给SQL语句的占位符问号?传值。可以避免SQL注入的风险。 ${}:底层使用Statement。特点:先进行SQL语句的拼接,然后再对SQL语…...
泛型类相关
package com.test.test02;/* * GenericTest就是一个普通的类 * GenericTest<E>就是一个泛型类 * <>里面就是一个参数类型,但是这个类型是什么呢?这个类型现在是不确定的,相当于一个占位。 * 但是现在确定的是这个类型一定是一…...
一文速学数模-季节性时序预测SARIMA模型详解+Python实现
目录 前言 一、季节时间序列模型概述 二、SARIMA模型定义 三.SARIMA模型算法原理...
二叉树与图(C++刷题笔记)
二叉树与图(C刷题笔记) 113. 路径总和 II 力扣 从根节点深度遍历二叉树,先序遍历时,将节点存储至path栈中,使用path_val累加节点值 当遍历到叶子节点,检查path_val是否为sum,若是,…...
STM32-ADC多通道输入实验
之前已经介绍了几个ADC的笔记和实验了,链接如下: 关于ADC的笔记1_Mr_rustylake的博客-CSDN博客 STM32-ADC单通道采集实验_Mr_rustylake的博客-CSDN博客 STM32-单通道ADC采集(DMA读取)实验_Mr_rustylake的博客-CSDN博客 接下来…...
javaIO流之文件流
目录 简介一、File的构造方法二、File的常用方法1、获取功能的方法2、绝对路径和相对路径3、判断功能的方法4、创建、删除功能的方法5、目录的遍历6、递归遍历 三、RandomAccessFile1、主要方法 四、Apache FileUtils 类1、复制文件或目录:2、删除文件或目录&#x…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
