【JS】JavaScript 中的原型与原型链

news2024/11/15 12:06:05

JavaScript 中的原型与原型链

      • 原型
        • 1 函数中 prototype 指向原型对象
        • 2 对象中 __proto__ 指向原型对象
        • 3 原型对象中 constructor 指向构造函数
        • 4 __proto__ 与 [[Prototype]] 的关系
        • 5 所有非空类型数据,都具有原型对象
        • 6 new运算符做了哪些事情
      • 原型链
        • 1 举个栗子
          • 1.1 直接创建一个对象
          • 1.2 数字、字符串、数组等类型数据, 下面以数字为例, 其他类型大同小异
          • 1.3 一个复杂的例子
        • 2 原型链的作用

原型

1 函数中 prototype 指向原型对象

当我们创建一个函数时,函数都会有一个默认属性 prototype

该属性指向一个对象, 该对象就被称之为 原型对象

function fun(){

}
fun.prototype // 原型对象

在这里插入图片描述

2 对象中 proto 指向原型对象

当函数作为 普通函数 进行调用时,该属性不会有任何作用

当函数被作为 构造函数 进行调用 (使用 new 运算符调用) 时,构建出来的 实例对象 会有一个属性 __proto__ 指向 原型对象

function fun(name){
  this.name = name
}

fun.prototype // 原型对象

// 函数被作为构造函数进行调用
const obj = new fun('swim') 

// 实例对象.__proto__ 指向 构造函数.prototype
obj.__proto__ === fun.prototype // true

》》》2

3 原型对象中 constructor 指向构造函数

原型对象 默认会有一个特殊的属性 constructor, 该属性又指向了函数本身

function fun(name){
  this.name = name
}

fun.prototype // 原型对象

// 原型对象中 constructor 指向构造函数
fun.prototype.constructor === fun // true

在这里插入图片描述

4 proto 与 [[Prototype]] 的关系

如果将 实例对象 打印出来, 会发现对象中并不具有 __proto__ 属性,恰恰相反有个特殊的 [[Prototype]] 属性。

《《《《4

__proto__ 并不是 ECMAScript 语法规范的标准, 它只是大部分浏览器厂商实现或说是支持的一个属性, 通过该属性方便我们访问、修改原型对象

遵循 ECMAScript 标准, [[Prototype]] 才是正统, [[Prototype]] 无法被直接修改、引用

ECMAScript 6 开始, 可通过 Object.getPrototypeOf()Object.setPrototypeOf() 来访问、修改 原型对象

简单理解: __proto__[[Prototype]] 是同一个东西, __proto__ 是非标准的, [[Prototype]] 才是标准的, 但是它们都是指向 原型对象

那么问题来了, 我们访问的 __proto__ 在哪里呢? 实际上它是被添加在 Object.prototype 上, 然后通过 原型链(后面会详细展开说明) 我们就能够访问到该属性

5 所有非空类型数据,都具有原型对象

任何非空数据,本质上都是通过对应的构造函数构建出来的,所以他们都具有 __proto__ 属性,指向构造函数的原型对象。

如果需要判断某个值的原型对象,只需要确认该值是通过哪个构造函数构建的即可,只要确认了构造函数,那么该值的 __proto__ 必然指向该构造函数的原型对象 prototype

// 数字
const num = 1
// 数字是通过 Number 构建的, 那么其原型对象等于 Number.prototype
num.__proto__ === Number.prototype // true

// 字符串
const str = 'str'
// 字符串是通过 String 构建的, 那么其原型对象等于 String.prototype
str.__proto__ === String.prototype // true

// 布尔类型
const bool = false
// 布尔值是通过 Boolean 构建的, 那么其原型对象等于 Boolean.prototype
bool.__proto__ === Boolean.prototype // true

// Symbol
const sym = Symbol('symbol')
// sym 是通过 Symbol 构建的, 那么其原型对象等于 Symbol.prototype
sym.__proto__ === Symbol.prototype // true

// BigInt
const big = BigInt(1)
// big 是通过 BigInt 构建的, 那么其原型对象等于 BigInt.prototype
big.__proto__ === BigInt.prototype // true

// 对象
const obj = { age: 18 }
// 对象是通过 Object 构建的, 那么其原型对象等于 Object.prototype
obj.__proto__ === Object.prototype // true

// 函数
const fun = () => {}
// 函数是通过 Function 构建的, 那么其原型对象等于 Function.prototype
fun.__proto__ === Function.prototype // true

// 数组
const arr = [1, 2, 3]
// 数组是通过 Array 构建的, 那么其原型对象等于 Array.prototype
arr.__proto__ === Array.prototype // true

6 new运算符做了哪些事情
  1. 创建一个新的空对象 A
  2. 往空对象挂载 构造函数 Com原型对象: 对象 A 创建 __proto__ 属性, 并将 构造函数prototype 属性赋值给 __proto__
  3. 执行 构造函数 Com: 改变 构造函数 this 指向, 指向空对象 A, 并执行 构造函数, 往空对象注入属性
  4. 判断 构造函数 是否返回一个对象?
  • 是: 如果 构造函数 也返回了一个对象 B, 则最终 new 出来的对象则为返回的对象 B
  • 否: 最终 new 出来的对象为最初创建的对象 A
因此当我们执行
var o = new Foo();

实际上执行的是:
// 1. 创建一个新的空对象 A
let A = {};

// 2. 往空对象挂载, 挂载构造函数 Com 的原型对象: obj.__proto__ === Com.prototype;
Object.setPrototypeOf(A, Com.prototype);

// 3. 执行构造函数: 改变构造函数 this 指向, 指向对象 A, 往 A 注入属性
let B = Com.apply(A, args);

// 4. 判断构造函数是否返回对象: 是则取返回值、否则取最初创建的对象 A
const newObj = B instanceof Object ? res : A;

原型链

原型链是一种对象之间的链接机制,它用于实现对象之间的继承和属性访问。

每个JavaScript对象都有一个原型(prototype),原型是一个对象或null。当你访问一个对象的属性时,如果该对象自身没有该属性,JavaScript 引擎会沿着原型链向上查找,直到找到具有该属性的对象或到达原型链的末尾(即null)。这样,对象可以继承其原型的属性和方法。

根据上文,所有非空数据,都可以通过 __proto__ 指向原型对象,如果原型对象非空,那么必然会有 __proto__ 指向自己的原型对象,如此一层一层往上追溯,依此类推,就形成了一整条链路,一直到某个原型对象为null,才能达到最后一个链路的最后环节,而原型对象之间这种链路关系被称之为原型链 (prototype chain)

1 举个栗子
1.1 直接创建一个对象
const obj = { age: 18 };

从对象 obj 视角来看:
1. obj 本质上是通过 Object 构建出来的,那么 obj.__proto__ === Object.prototype
2. Object.prototype 的原型对象为 null,因此原型链到此结束

》》》图5

1.2 数字、字符串、数组等类型数据, 下面以数字为例, 其他类型大同小异
let num = 1;

1. num 本质上是通过 Number 构建出来的,那么 num.__proto__ === Number.prototype
2. Number.prototype 本质上是一个对象,是通过 Object 构建出来的,
	那么 Number.prototype.__proto__ === Object.prototype
3. Object.prototype 的原型对象为 null,因此原型链到此结束

num.__proto__ === Number.prototype // true
Number.prototype.__proto__ === Object.prototype // true
Object.prototype.__proto__  // null 原型链结束
1.3 一个复杂的例子
function Person(age) {
  this.age = age       
}
var person = new Person(100)

从对象  person 视角来看:
	1. person 是通过 Person 构建出来的, 那么 person.__proto__ 等于 Person.prototype
	2. Person.prototype 是个对象, 是通过 Object 构建出来了, 那么Person.prototype.__proto__ 等于 Object.prototype
	3. Object.prototype 的 原型对象 为 null, 原型链 到此结束

2 原型链的作用
  • 查找属性: 当我们试图访问 对象属性 时, 它会先在 当前对象 上进行搜寻, 搜寻没有结果时会继续搜寻该对象的 原型对象, 以及该对象的 原型对象原型对象, 依次层层向上搜索, 直到找到一个名字匹配的属性或到达原型链的末尾
function Person(age) {
  this.age = age
}

Person.prototype.name = 'klx'
Person.prototype.age = 18

const person = new Person(28)

person // 当前对象: { age: 28 }

person.name // klx, 取自原型对象 Person.prototype
person.age // 28, 取自当前对象

person.toString() // [object Object], 取自原型对象 Object.prototype

person.address // undefined, 沿着原型链找不到 address 

  • 继承属性和方法:原型链允许对象继承其原型的属性和方法。当你访问一个对象的属性时,如果对象本身没有该属性,它会通过原型链访问原型对象的属性。这样可以实现属性的共享和代码的重用。

  • 创建对象关联:通过原型链,你可以将一个对象与另一个对象关联起来,形成一个对象链。这样,一个对象可以通过原型链访问到另一个对象的属性和方法。

  • 实现对象的多态性:在原型链中,可以通过在原型对象上定义相同名称的属性或方法,从而实现对象的多态性。当对象在原型链中找到具有相同名称的属性或方法时,会使用最近的那个

JavaScript中的原型链是基于原型继承的概念,它允许对象通过原型链接到其他对象,并继承其属性和方法。这种机制在JavaScript中是一种重要的特性,使得对象之间可以实现继承和共享,提供了灵活性和代码复用的机制。

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

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

相关文章

[linux]--关于进程概念(下)

目录 孤儿进程 环境变量 将程序放到PATH路径下 设置PATH环境变量 设置别名 环境变量相关的命令 环境变量的组织方式​编辑 通过系统调用获取环境变量 环境变量通常是具有全局属性的 进程优先级 查看系统进程 用top命令更改已存在进程的nice: 程序地址空…

mac下Appuim环境安装-持续更新中

参考资料 Mac安装Appium_mac电脑安装appium-CSDN博客 安卓测试工具:Appium 环境安装(mac版本)_安卓自动化测试mac环境搭建-CSDN博客 1. 基本环境依赖 1 node.js 2 JDK(Java JDK) 3 Android SDK 4 Appium&#x…

数据库系统概论-第14章 大数据管理

14.1 大数据概述 14.2 大数据的应用 14.3 大数据管理系统 14.4 小结

3D轻量引擎HOOPS SDK:EDA应用程序高效开发利器

电子设计自动化(EDA)软件在现代工程实践中扮演着至关重要的角色。随着技术的不断进步和市场的竞争加剧,开发高效、可靠的EDA应用程序成为了行业内的一项迫切需求。在这一背景下,Tech Soft 3D的HOOPS SDK(Software Deve…

灵境矩阵平台x百度---智能体(一)

什么是数据插件 大模型插件:大语言模型插件是随着大语言模型发展而诞生的全新插件。大语言模型插件的核心是Web API独立于大语言模型,插件开发过程不受大语言模型的约束,同时没有开发语言的限制,更加通用,只要WebAPI遵循RESTfuI相…

步进电机驱动器的接线与使用(接线详细)

今天小编就来继续学习与使用步行电机的学习,如果位置对你有帮助,评论收藏,点赞一下 步进电机驱动器 步进电机驱动器是一种专用于控制步进电机的电子设备,用于控制步进电机的转动和位置。步进电机是一种将电信号转换为机械运动的电…

R包安装失败怎么办?(一)msigdbr

R包安装失败 如果是网络原因(error connection),就使用本地安装的方法。如果是网络原因,通常会出现安装超时,或者网络无法连接的提示 当你把timeout 设置到1000之后还会报错,怎么办? options…

【jvm】jinfo使用

jinfo介绍 jinfo 是一个命令行工具,用于查看和修改 Java 虚拟机(JVM)的配置参数。它通常用于调试和性能调优。 使用 jinfo 命令,你可以查看当前 JVM 的配置参数,包括堆大小、线程数、垃圾回收器类型等。此外&#xf…

基于单片机的四旋翼飞行器的设计与实现

摘 要:四旋翼飞行器可以垂直升降,应用于军事和民用领域,在飞行器的设计中,结合单片机进行设计,可以提升整体性能。基于此,本文探究基于单片机的四旋翼飞行器设计与实现,探索飞行器的硬件设计和软件设计方案,并且对系统的角速度算法以及姿态控制算法进行测试,最后对系…

六大排序精解

排序概念 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序&#x…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之四 简单复古怀旧照片效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之四 简单复古怀旧照片效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之四 简单复古怀旧照片效果 一、简单介绍 二、简单复古怀旧照片效果实现原理 三、简单复古怀旧照片效果案例实现…

开源Thinkphp核心在线网页音乐播放php源码,附带系统搭建教程

安装教程 环境要求:apachePHP7.0Thinkphp伪静态 安装教程:修改Application目录下的database.php信息 导入根目录下的install.sql到数据库 修改Static目录下的player目录下的player.js文件的第140行的“域名”为你的域名 修改Static目录下的player2目录下…

Godot 学习笔记(4):一切以场景为中心

文章目录 前言场景搭建新建子场景最简单的按钮事件 手动控制场景手动加载场景添加多个场景对象更快速的获取脚本对象 删除多个场景对象脚本命名的问题 总结 前言 Godot的场景是C#与Godot最后的中间连接。我们解决了场景的加载,我们基本可以保证C#和godot之间的彻底…

ModbusRTU/TCP/profinet网关在西门子博图软件中无法连接PLC的解决方法

ModbusRTU/TCP/profinet网关在西门子博图软件中无法连接PLC的解决方法 在工业生产现场,ModbusRTU/TCP/profinet网关在与西门子PLC连接时,必须要使用西门子的博图软件来进行配置,博图v17是一个集成软件平台,专业版支持300、400、12…

【碳资产管理/精细化能源管控】Acrel-7000企业能源管控平台

工厂企业用能需求 能源管理 安科瑞薛瑶瑶18701709087 生产全过程用能数据监测和分析;完善并落实能源管理制度,使之更有效的运行;量化能效考核kpi,用数据说明问题。 用能安全 完善用能安全监测,保障人身与电气设备…

【计算机】——51单片机

单片机是一种内部包含CPU、存储器和输入/输出接口等电路的集成电路(IC芯片) 单片机是单片微型计算机(Single Chip Microcomputer)的简称,用于控制领域,所以又称为微型控制器(Microcontroller U…

ubuntu20.04搭建nginx rtmp视频服务到指定位置解决权限不足

1.安装依赖 apt-get install build-essential libpcre3 libpcre3-dev libssl-dev2.建一个目录 mldir rtmp_nginx 3.源码下载 wget http://nginx.org/download/nginx-1.21.6.tar.gz wget https://github.com/arut/nginx-rtmp-module/archive/master.zip4.解压缩 tar -xf ng…

RabbitMQ--04--Spring Cloud Stream(消息驱动)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1.Spring Cloud Stream1. 基本介绍https://spring.io/projects/spring-cloud-stream#overview 2.Spring Cloud Stream 解决的痛点问题3.设计思想Stream为什么可以统…

游戏平台出海运营有难度吗?

随着全球互联网的飞速发展,游戏产业已经成为了文化娱乐领域的重要支柱。在这个背景下,越来越多的游戏平台开始寻求出海运营,以拓展海外市场,实现更大的商业价值。然而,游戏平台出海运营并非易事,其中涉及到…

【深度学习】最强算法之:深度神经网络(DNN)

深度神经网络 1、引言2、深度神经网络2.1 定义2.2 原理2.3 实现方式2.4 算法公式2.4.1 前向传播公式2.4.2 反向传播公式 2.5 代码示例 3、总结 1、引言 小屌丝:鱼哥,我遇到难题了 小鱼:然后呢 小屌丝:你帮我看看呗? 小…