JavaScript---原型和原型链

news2025/4/18 19:42:59

目录

一、引用类型皆为对象

二、原型和原型链是什么

三、__proto__与prototype

总结

四、原型链顶层

五、constructor

六、函数对象的原型链


一、引用类型皆为对象

原型原型链都是来源于对象而服务于对象

  • JavaScript中一切引用类型都是对象,对象就是属性的集合
  • Array、Function、Object、Date、RegExp都是引用类型
  • 数组是对象、函数是对象、正则是对象、对象还是对象
const arr = []
const fn = function() {}
const obj = {}

console.log(typeof arr) // "object"
console.log(fn instanceof Object) // true
console.log(typeof obj) // "object"

二、原型和原型链是什么

每一个对象从被创建开始就和另一个对象关联,从另一个对象上继承其属性,这个“另一个对象”就是“原型

当访问一个对象的属性时,先在对象的本身查找,找不到就去对象的原型上找,如果还找不到,就去对象的原型的原型上去找,如此重复,直到找到为止,或者查找到最顶层的原型对象中也没有找到,就结束查找,返回undefined

而在对象的原型上,依次查找时,所遍历的所有原型,叫作“原型链

const obj = {}
obj.sayHello = () => {console.log('Hello')}
console.log(obj.hasOwnProperty('sayHello')) // true
  • 上面代码中,我们访问obj.hasOwnProperty()时,发现该对象并没有这个方法,但是我们仍然可以使用,这是因为在obj对象的原型上,存在该方法,所以我们可以调用
  • 到现在,我们可以理解数组可以使用push、slice等方法,函数可以使用call、bind方法了,因为在它们的原型链上找到了对应的方法

三、__proto__与prototype

每个对象都有原型,我们怎么获取到一个对象的原型呢?可以使用对象的“__proto__”属性,指向对象的原型

  • 所有引用类型都有__proto__属性

  • __proto__属性在ES6中不推荐被使用,现在更推荐使用Obejct.getPrototypeOf(),该方法也可以获取到对象的属性
console.log(Object.getPrototypeOf(obj) === obj.__proto__) // true

构造函数是为了创建特定类型的对象,那如果我想让“Person”这个构造函数创建的对象都共享一个方法,不能像下面这样:

错误示范:

function Person(name){
    this.name = name;
}
// 调用构造函数Person创建一个新对象PersonA
const personA = new Person();
// 给PersonA的原型添加一个方法,以供之后Person创建的对象共享
personA.__proto__.sayHello = function(){
    console.log(`Hello, my name is ${this.name}`);
}
// 创建一个新的Person对象PersonB
const personB = new Person('Bob');
// 调用PersonB的sayHello方法
personB.sayHello(); // Hello, my name is Bob
  • 当我们不想修改构造函数创建的对象,并且还不想修改构造函数时,如果先通过构造函数创建一个对象,再通过对象的原型修改,这样确实可以,但实在太过啰嗦

为此,我们可以通过“prototype”来直接修改原型,每个函数多拥有prototype属性,指向使用new操作符和该函数创建的对象的实例的原型对象

console.log(personA.__proto__ === Person.prototype); // true
console.log(personB.__proto__ === Person.prototype); // true

正确示范:

function Person(name){
    this.name = name;
}
Person.prototype.sayHello = function(){
    console.log(`Hello, my name is ${this.name}`);
}
const personA = new Person('Bob');
personA.sayHello(); // Hello, my name is Bob

总结

  • 对象有__proto__属性(Object.create(null)除外),函数有__proto__属性,数组也有__proto__属性,只要是引用类型,就有__proto__属性,指向其原型
  • 只有函数有prototype属性,指向new操作符加调用该函数创建的对象实例的原型对象

四、原型链顶层

原型链之所以叫原型链,不叫原型环,说明它是有始有终的,那么原型链的顶层是什么呢?

personA对象的原型对象,很简单:

console.log(personA.__proto__ === Person.prototype); 

接着往上找,Person.prototype也是一个普通对象,可以理解为Object构造函数创建的,所以得出下面结论:

console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Person.prototype.__proto__)

  • 上图红框内的__proto__就是Person.prototype.__proto__,也就是下图:

Object.protype也是一个对象,那么它的原型呢?是空值null

Object.prototype.__proto__ === null

五、constructor

构造函数都有一个prototype属性,指向使用这个构造函数创建的对象实例的原型对象

这个原型对象中默认有一个constructor属性,指回该构造函数

Person.prototype.constructor === Person // true

六、函数对象的原型链

函数也是对象,故函数也有__proto__属性,这里比较容易混淆

因为函数既有prototype也有__proto__,很容易搞晕

我们只需要记住:

  • 函数的prototype使用的前提是:“函数被作为构造函数使用,此时prototype指向构造函数创建的对象实例的__proto__原型对象”
  • 函数的__proto__指的是:“函数被当做一个普通对象使用,此时它的__proto__指向Function.prototype,因为Function是所有函数的构造函数”
  • 一个特例,Fyunction.__prototype === Function.prototype,记住就好
console.log(Person.__proto__ === Function.prototype) // true
console.log(Person.__proto__.constructor === Function) // true
console.log(Person.__proto__.__proto__ === Object.prototype) // true

有点绕,但是理解这三个代码,相信__proto__prototype你永远不会弄混了

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

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

相关文章

离散数学问题集--问题5.9

问题 5.9 综合了计算机组成原理、数字逻辑和离散数学中的关键概念,旨在帮助学生理解二进制算术运算的硬件实现、逻辑门与算术运算的关系,以及如何使用数学方法来验证数字系统的正确性。它强调了从规范到实现再到验证的完整过程。 思想 函数抽象&#xf…

Java—HTML:CSS选择器

今天我要介绍的知识点内容是Java HTML中的CSS选择器; CSS选择器用于定位HTML元素并为其添加样式。它允许我们控制网页的颜色、字体、布局和其他视觉元素。通过分离内容与样式。 下面我将介绍CSS中选择器的使用,并作举例说明; 选择器基本语…

SSM阶段性总结

0 Pojo类 前端给后端:DTO 后端给前端:VO 数据库:PO/VO 业务处理逻辑:BO 统称pojo 1 代理模式 实现静态代理: 1定义接口2实现类3写一个静态代理类4这样在调用时就可以使用这个静态代理类来实现某些功能 实现动态代…

Qt 5.14.2入门(一)写个Hello Qt!程序

目录 参考链接:一、新建项目二、直接运行三、修改代码增加窗口内容1、Qt 显示一个 QLabel 标签控件窗口2、添加按键 参考链接: Qt5教程(一):Hello World 程序 Qt 编程指南 一、新建项目 1、新建一个项目&#xff08…

Jmeter分布式测试启动

代理客户端配置 打开jmeter.properties文件,取消注释并设置端口(如server_port1099), 并添加server.rmi.ssl.disabletrue禁用SSL加密。 (Linux系统)修改jmeter-server文件中的RMI_HOST_DEF为代理机实际IP。…

redis itheima

缓存问题 核心是如何避免大量请求到达数据库 缓存穿透 既不存在于 redis,也不存在于 mysql 的key,被重复请求 public Result queryById(Long id) {String key CACHE_SHOP_KEYid;// 1. redis & mysqlString shopJson stringRedisTemplate.opsFo…

100天精通Python(爬虫篇)——第122天:基于selenium接管已启动的浏览器(反反爬策略)

文章目录 1、问题描述2、问题推测3、解决方法3.1 selenium自动启动浏览器3.2 selenium接管已启动的浏览器3.3 区别总结 4、代码实战4.1 手动方法(手动打开浏览器输入账号密码)4.2 自动方法(.bat文件启动的浏览器) 1、问题描述 使用…

MPP 架构解析:原理、核心优势与对比指南

一、引言:大数据时代的数据处理挑战 全球数据量正以指数级增长。据 Statista 统计,2010 年全球数据量仅 2ZB,2025 年预计达 175ZB。企业面临的核心挑战已从“如何存储数据”转向“如何快速分析数据”。传统架构在处理海量数据时暴露明显瓶颈…

Python设计模式-工厂模式

一、模式定义与核心思想 工厂模式(Factory Pattern)属于创建型设计模式,其核心思想是通过一个"工厂类"来创建对象,而不是直接调用类的构造函数。这种模式将对象的实例化过程封装起来,使系统在实例化对象时能…

彻底解决VS2008编译错误:fatal error C1083 无法打开包括文件“stdint.h“

彻底解决VS2008编译错误:fatal error C1083 无法打开包括文件"stdint.h" 一、错误现象与本质原因 当在Visual Studio 2008中编译包含C99标准整数类型(如int8_t、uint32_t)的代码时,常出现以下编译错误: f…

react从零开始的基础课

全文约5万字。 1.hello,.. // App.jsx import { useState } from react import reactLogo from ./assets/react.svg import viteLogo from /vite.svg import ./App.cssfunction App() {const [count, setCount] useState(0)return (<><Greeting name"world&qu…

算法题型讲解

一.双指针 主要分为俩种类型&#xff1a; 1.左右指针&#xff1a;双指针指向开头&#xff0c;以一定标准移动或交换&#xff0c;对区域进行划分&#xff0c;或找到特殊点的位置 &#xff08;如&#xff1a;快慢指针判断有无环&#xff0c;移动零&#xff09; 2.对撞指针&am…

Redis和数据库一致性问题

操作模拟 1、先更新数据库还是先更新缓存&#xff1f; 1.1先更新缓存&#xff0c;再更新数据库 按并发的角度来说&#xff0c;有两个线程A、B&#xff0c;操作同一个数据&#xff0c;线程A先更新缓存为1&#xff0c;在线程A更新数据库之前&#xff0c;这时候线程B进来&#…

第R8周:RNN实现阿尔茨海默病诊断(pytorch)

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营]中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊]** 本人往期文章可查阅&#xff1a; 深度学习总结 一、准备工作 &#x1f3e1; 我的环境&#xff1a; 语言环境&#xff1a;Python3.1…

C++基础精讲-02

文章目录 1.C/C申请、释放堆空间的方式对比1.1C语言申请、释放堆空间1.2C申请、释放堆空间1.2.1 new表达式申请数组空间 1.3回收空间时的注意事项1.4malloc/free 和 new/delete 的区别 2.引用2.1 引用的概念2.2 引用的本质2.3 引用与指针的联系与区别2.4 引用的使用场景2.4.1 引…

【网络安全】Linux 命令大全

未经许可,不得转载。 文章目录 前言正文文件管理文档编辑文件传输磁盘管理磁盘维护网络通讯系统管理系统设置备份压缩设备管理其它命令前言 在网络安全工作中,熟练掌握 Linux 系统中的常用命令对于日常运维、日志分析和安全排查等任务至关重要。 以下是常用命令的整理汇总,…

C++学习之ORACLE①

目录 1.ORACLE数据库简介 2..ORACLE数据库安装 3..ORACLE体系结构 4..ORACLE基本概念 5..ORACLE基本元素 6..ORACLE数据库启动和关闭 7.SQLPLUS登录ORACLE数据库相关操作 8.SQLPLUS的基本操作 9.oracle中上课使用的方案 10.SQL语言分类 11.SQL中的select语句语法和注…

企业级开发SpringBoost玩转Elasticsearch

案例 Spring Boot 提供了 spring-data-elasticsearch 模块&#xff0c;可以方便地集成 Elasticsearch。 下面我们将详细讲解如何在 Spring Boot 中使用 Elasticsearch 8&#xff0c;并提供示例代码。 1. 添加依赖: 首先&#xff0c;需要在 pom.xml 文件中添加 spring-data-e…

从零开始的图论讲解(1)——图的概念,图的存储,图的遍历与图的拓扑排序

目录 前言 图的概念 1. 顶点和边 2. 图的分类 3. 图的基本性质 图的存储 邻接矩阵存图 邻接表存图 图的基本遍历 拓扑排序 拓扑排序是如何写的呢? 1. 统计每个节点的入度 2. 构建邻接表 3. 将所有入度为 0 的节点加入队列 4. 不断弹出队头节点&#xff0c;更新其…

SpringBoot框架—启动原理

1.SpringBootApplication注解 在讲解启动原理之前先介绍一个非常重要的注解SpringBootApplication&#xff0c;这个注解在Springboot程序的入口文件Application.java中必须添加。SpringBootApplication是一个整合了三个核心注解的组合注解。 三个核心注解的作用机制&#xff1…