当前位置: 首页 > news >正文

简述 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]] 的方法有两种:

  1. __proto__

    已经 Deprecated 了,deno 中甚至不支持实现

  2. 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 的作用在于

  1. 它创建了一个新的对象
  2. 它关联了对应的原型链继承
  3. 它绑定了 this 的指向
  4. 它执行了构造函数内的部分

一个简单的实现 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 了。

superthis

到这一步,基本上使用 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();

在这里插入图片描述

接下来要模拟实现的就是这一步,其中需要注意的就是:

  1. 实现继承关系

    这点可以通过修改 prototype 进行实现,已知 [[Prototype]] 中包含了所有的 prototype chain,这里也只需要将 Child.prototype 指向 Parent.prototype,并且绑定对应的 构造函数即可。

  2. 修改 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 这篇笔记主要捋一下这么几个概念&#xff1a; JS 的继承构造函数new 的作用及简易实现__proto__ & prototype同样的方法&#xff0c;class 和 prototype 中分别是怎么实现的 基础概念 JS 是通过 prototype chaining 实现继承的语言&#…...

一觉醒来Chat gpt就被淘汰了

目录 什么是Auto GPT&#xff1f; 与其他语言生成模型相比&#xff0c;Auto GPT具有以下优点 Auto GPT的能力 Auto GPT的能力非常强大&#xff0c;它可以应用于各种文本生成场景&#xff0c;包括但不限于以下几个方面 Auto GPT的历史 马斯克说&#xff1a;“ChatGPT 好得吓…...

13款JavaScript图像处理库,建议收藏备用

pica&#xff1a; 一个在浏览器中调整图像大小&#xff0c;而不会出现像素失真&#xff0c;处理速度非常快的图片处理库&#xff0c;仓库地址https://github.com/nodeca/picahtml2canvas&#xff1a; 强大的使用js开发的浏览器网页截图工具&#xff0c;仓库地址https://github.…...

uniapp m3u8格式视频加载

uniapp一&#xff1a;mui-player&#xff1a;三方 h5 web app uniapp 使用 mui-player 插件播放 m3u8/flv 视频流_翘翘红的博客-CSDN博客 uniapp 开发的h5项目&#xff0c;需要播放m3u8/flv后缀的视频&#xff0c;网上有很多视频插件&#xff0c;但是样式和效果不尽如人意&am…...

iOS描述文件(.mobileprovision)一键申请

iOS描述文件(.mobileprovision)一键申请 在主界面上点击描述文件按钮。 新建ios描述文件 然后点击新建&#xff0c;然后输入描述文件名称&#xff0c;描述文件名称字符和数字&#xff0c;自己好辨识就可以。然后选择描述文件类型&#xff0c;再选择bundle ID&#xff0c;如果…...

进行性能压力测试的原因、目的和好处

性能压力测试是指在模拟高负载、高并发情况下对软件系统进行测试&#xff0c;以衡量系统在实际使用过程中的性能表现。这些测试可以为生产环境中的应用程序提供关键数据&#xff0c;并帮助开发人员从根本上了解系统的实际性能。在本文中&#xff0c;我们将探讨进行性能压力测试…...

【计算机视觉】如何利用 CLIP 做简单的人脸任务?(含源代码)

文章目录 一、数据集介绍二、源代码 结果三、代码逐行解读 一、数据集介绍 CELEBA 数据集&#xff08;CelebFaces Attributes Dataset&#xff09;是一个大规模的人脸图像数据集&#xff0c;旨在用于训练和评估人脸相关的计算机视觉模型。该数据集由众多名人的脸部图像组成&a…...

基于显扬科技3D视觉相机的医疗试管分拣系统

行业现状&#xff1a; 医疗试管分拣是医疗行业中的一个重要环节&#xff0c;指将医疗实验室或生物技术研究中的试管按照一定的规则进行分拣&#xff0c;并对试管的类型、位置、数量等信息进行识别和管理。 随着医疗技术的不断发展和诊断治疗的精细化&#xff0c;医疗试管分拣…...

编译zlib

zlib被设计为一个免费的&#xff0c;通用的&#xff0c;法律上不受限制的-即不受任何专利保护的无损数据压缩库&#xff0c;几乎可以在任何计算机硬件和操作系统上使用。 官网&#xff1a;http://www.zlib.net/ 下载zlib源码:http://www.zlib.net/zlib1213.zip 备用地址&#x…...

如何让“ChatGPT自己写出好的Prompt的“脚本在这里

写个好的Prompt太费力了 在网上&#xff0c;你可能会看到很多人告诉你如何写Prompt&#xff0c;需要遵循各种规则&#xff0c;扮演不同的角色&#xff0c;任务明确、要求详细&#xff0c;还需要不断迭代优化。写一个出色的Prompt需要投入大量的时间和精力。甚至有一些公开的Pr…...

菜单选择shell

[rootes3 data]# vi action.sh #!/bin/bash . /etc/init.d/functionsecho -en "\E[$[RANDOM%731];1m"cat <<EOF请选择&#xff1a;1) 备份数据库2)清理日志3)软件升级4)软件回滚5)删库跑路EOFecho -en \E[0mread -p "请选择上面的项对应的数字1-5&#xf…...

Redis高可用性详解

目录 ​编辑 高可用性&#xff1a; 主从复制&#xff08;Master-Slave Replication&#xff09;&#xff1a; 主从复制的一般工作流程&#xff1a; 哨兵模式&#xff08;Sentinel Mode&#xff09;&#xff1a; 哨兵模式的一般工作流程&#xff1a; 集群模式&#xff08…...

MySQL(1) ---- 数据库介绍与MySQL概述

介绍 1、什么是数据库&#xff1f; 数据库&#xff1a;DateBase&#xff08;DB&#xff09;&#xff0c;是存储和管理数据的仓库。数据库管理系统&#xff1a;DataBase Management System&#xff08;DBMS&#xff09;&#xff0c;操纵和管理数据库的大型软件。SQL&#xff1…...

面试题之软件测试流程

说说公司的软件测试流程&#xff0c;这&#xff0c;是常考的面试题之一。 不同公司的流程不一样&#xff0c;现状决定流程&#xff0c;没有绝对的对错。 以结果为导向&#xff0c;保证产品质量&#xff0c;提高测试效率&#xff0c;才是王道。 以下的流程为业界比较标准的流程&…...

MyBatis中#{}与${}的区别,与各自的应用场景

#{}和${}的区别&#xff1a; #{}: 底层使用PreparedStatement。特点&#xff1a;先进行SQL语句的编译&#xff0c;然后给SQL语句的占位符问号?传值。可以避免SQL注入的风险。 ${}&#xff1a;底层使用Statement。特点&#xff1a;先进行SQL语句的拼接&#xff0c;然后再对SQL语…...

泛型类相关

package com.test.test02;/* * GenericTest就是一个普通的类 * GenericTest<E>就是一个泛型类 * <>里面就是一个参数类型&#xff0c;但是这个类型是什么呢&#xff1f;这个类型现在是不确定的&#xff0c;相当于一个占位。 * 但是现在确定的是这个类型一定是一…...

一文速学数模-季节性时序预测SARIMA模型详解+Python实现

目录 前言 一、季节时间序列模型概述 二、SARIMA模型定义 三.SARIMA模型算法原理...

二叉树与图(C++刷题笔记)

二叉树与图&#xff08;C刷题笔记&#xff09; 113. 路径总和 II 力扣 从根节点深度遍历二叉树&#xff0c;先序遍历时&#xff0c;将节点存储至path栈中&#xff0c;使用path_val累加节点值 当遍历到叶子节点&#xff0c;检查path_val是否为sum&#xff0c;若是&#xff0c…...

STM32-ADC多通道输入实验

之前已经介绍了几个ADC的笔记和实验了&#xff0c;链接如下&#xff1a; 关于ADC的笔记1_Mr_rustylake的博客-CSDN博客 STM32-ADC单通道采集实验_Mr_rustylake的博客-CSDN博客 STM32-单通道ADC采集&#xff08;DMA读取&#xff09;实验_Mr_rustylake的博客-CSDN博客 接下来…...

javaIO流之文件流

目录 简介一、File的构造方法二、File的常用方法1、获取功能的方法2、绝对路径和相对路径3、判断功能的方法4、创建、删除功能的方法5、目录的遍历6、递归遍历 三、RandomAccessFile1、主要方法 四、Apache FileUtils 类1、复制文件或目录&#xff1a;2、删除文件或目录&#x…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...