js原型和原型链

news2025/5/19 11:18:48

js原型:

1、原型诞生的目的是什么呢?

js原型的产生是为了解决在js对象实例之间共享属性和方法,并把他们很好聚集在一起(原型对象上)。每个函数都会创建一个prototype属性,这个属性指向的就是原型对象。

2、理解原型

无论何时,只要创建一个函数,就会为这个函数添加一个属性prototype,这个属性指向一个对象——原型对象。原型对象默认只有一个属性constructor(不可枚举属性),这个属性指回构造函数,另外其他的属性和方法都继承自Object.prototype。

构造函数通过new关键字调用创建对象实例。对象实例会有一个[[prototype]]属性指向函数的原型对象,js访问的话就是通过obj.__proto__指向构造函数原型对象。

注意:对象实例和构造函数之间没有直接的联系。但是通过对象实例obj.constructor是指向构造函数的,这是因为对象实例本身是没有constructor这个属性的,但是沿着原型链查找会找到原型上constructor是指向构造函数的。

关系图如上。

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

person.__proto__ === Person.prototype //true

可以看出,构造函数和函数原型是循环引用的关系。

3、几个关于原型的方法:

isPrototypeOf(): 对象实例上的方法,继承自Object.prototype

Person.prototype.isPrototypeOf(person)    //true

Object.getPrototypeOf():可以方便的获取一个对象的原型。

Object.getPrototypeOf(person)===Person.prototype  //true

Object.setPrototypeOf()和Object.create():设置对象的原型

1. Object.setPrototypeOf(obj, prototype)

  • 功能: 用于设置一个现有对象的原型。
  • 参数:
    • obj: 目标对象,其原型将被修改。
    • prototype: 要设置为目标对象原型的新对象(或 null)。
  • 返回值: 返回被修改的对象 obj
  • 用法:
    const obj = {};
    const proto = { greet: () => console.log('Hello!') };
    
    Object.setPrototypeOf(obj, proto);
    
    obj.greet(); // 输出: Hello!
  • 特点:
    • 修改的是现有对象的原型。
    • 如果目标对象的原型已经被设置为某个值,Object.setPrototypeOf() 会覆盖它。
    • 可能会影响性能,因为设置原型会破坏某些 JavaScript 引擎的优化。

2. Object.create(proto, [propertiesObject])

  • 功能: 创建一个新对象,并将该对象的原型设置为指定的对象。
  • 参数:
    • proto: 新对象的原型对象(或 null)。
    • propertiesObject(可选): 一个对象,其属性描述符用于定义新对象的自身属性。
  • 返回值: 返回一个新对象,其原型是 proto
  • 用法:
    const proto = { greet: () => console.log('Hello!') };
    const obj = Object.create(proto);
    
    obj.greet(); // 输出: Hello!
  • 特点:
    • 创建的是新对象,不会修改现有对象。
    • 更适合用于继承或创建具有特定原型的对象。
    • 性能通常优于 Object.setPrototypeOf(),因为它是专门为创建对象而设计的。

4、原型对象属性和对象实例属性的优先级

如果对象实例上定义了和原型对象上同名的属性,那么对象实例的属性会覆盖掉原型对象上的属性。

hasOwnProperty():对象实例上继承自Object.prototype上的方法。区分属性是在对象原型上还是对象实例上。

const obj = Object.create({ inheritedProp: 'value' });
obj.ownProp = 'myValue';

console.log(obj.hasOwnProperty('ownProp')); // true
console.log(obj.hasOwnProperty('inheritedProp')); // false

in操作符:当你需要检查属性是否存在于对象中(无论是自身属性还是继承属性)时,使用 in

const obj = Object.create({ inheritedProp: 'value' });
obj.ownProp = 'myValue';

console.log('ownProp' in obj); // true
console.log('inheritedProp' in obj); // true

5、关于自定义原型特别需要注意的问题

A)重写原型会切断原型对象和构造函数之间的联系,需要手动重新建立。给原型对象增加constructor属性(且不可枚举),指回构造函数。

function Person(name,age){
  this.name=name;
  this.age=age;
}

Person.prototype={
  name:'myName',
  age:99,
  job:'myjob',
  sayName(){
    console.log(this.name)
  }
}

Object.defineProperty(Person.prototype,'constructor',{
  value:Person
})

B)重写原型之前,使用构造方法创建出来的对象实例的__proto__指向的还是原来的原型对象。重写原型之后,再次创建出来的对象__proto__指向的才是新的原型对象。

function Person(name,age){
  this.name=name;
  this.age=age;
}

let person1=new Person('zhangsan',18)

Person.prototype={
  name:'myName',
  age:99,
  job:'myjob',
  sayName(){
    console.log(this.name)
  }
}

Object.defineProperty(Person.prototype,'constructor',{
  value:Person
})

let person2=new Person('lisi',19)

console.log(person1)
console.log(person2)

根据需要,可以将先前的创建对象实例的原型重新指定一下。

6、原型存在的问题

共享引用值的问题,如下:

function Person(name,age){
  this.name=name;
  this.age=age;
}
Person.prototype.friends=['a','b','c','d']

let person1=new Person('zhangsan',18)
let person2=new Person('lisi',19)

person1.friends.splice(1,1)
console.log(person1.friends)
console.log(person2.friends)

person1的friends少了一个,person2也跟着少了一个,像这种问题其实也不算问题。把friends属性变成对象实例自有的属性即可。

原型链:

1、理解原型链

理解了原型,原型链就很好理解了。其实呢,就是在你访问对象实例的属性时,查找属性的一条链路。先上图:

当你从对象实例person上访问某个属性时,先查找自有属性,然后到函数原型Person.prototype上查找,最后再到函数原型Object.prototype上查找,如果还是找不到,就会返回undefined或者报错。

2、理解Function和Object的关系:

内容较多,且难以理解。我将再写篇文章进行详细介绍,敬请关注。

一文搞懂JS中Function和Object的关系-CSDN博客

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

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

相关文章

OpenHarmony - 小型系统内核(LiteOS-A)(五)

OpenHarmony - 小型系统内核(LiteOS-A)(五) 六、文件系统 虚拟文件系统 基本概念 VFS(Virtual File System)是文件系统的虚拟层,它不是一个实际的文件系统,而是一个异构文件系统之…

PyTorch进阶学习笔记[长期更新]

第一章 PyTorch简介和安装 PyTorch是一个很强大的深度学习库,在学术中使用占比很大。 我这里是Mac系统的安装,相比起教程中的win/linux安装感觉还是简单不少(之前就已经安好啦),有需要指导的小伙伴可以评论。 第二章…

proteus8.17 环境配置

Proteus介绍 Proteus 8.17 是一款功能强大的电子设计自动化(EDA)软件,广泛应用于电子电路设计、仿真和分析。以下是其主要特点和新功能: ### 主要功能 - **电路仿真**:支持数字和模拟电路的仿真,包括静态…

Java对接Dify API接口完整指南

Java对接Dify API接口完整指南 一、Dify API简介 Dify是一款AI应用开发平台,提供多种自然语言处理能力。通过调用Dify开放API,开发者可以快速集成智能对话、文本生成等功能到自己的Java应用中。 二、准备工作 获取API密钥 登录Dify平台控制台在「API密…

极狐GitLab GEO 功能介绍

极狐GitLab 是 GitLab 在中国的发行版,关于中文参考文档和资料有: 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 Geo (PREMIUM SELF) Geo 是广泛分布的开发团队的解决方案,可作为灾难恢复策略的一部分提供热备份。Geo 不是 开箱…

云原生(Cloud Native)的详解、开发流程及同类软件对比

以下是云原生(Cloud Native)的详解、开发流程及同类软件对比: 一、云原生核心概念 定义: 云原生(Cloud Native)是基于云环境设计和运行应用程序的方法论,强调利用云平台的弹性、分布式和自动化…

学习笔记:减速机工作原理

学习笔记:减速机工作原理 一、减速机图片二、减速比概念三、减速机的速比与扭矩之间的关系四、题外内容--电机扭矩 一、减速机图片 二、减速比概念 即减速装置的传动比,是传动比的一种,是指减速机构中,驱动轴与被驱动轴瞬时输入速…

《UE5_C++多人TPS完整教程》学习笔记36 ——《P37 拾取组件(Pickup Widget)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P37 拾取组件(Pickup Widget)》 的学习笔记,该系列教学视频为计算机工程师、程序员、游戏开发者、作家(Engineer, Programmer, Game Developer, Author) Steph…

《空间复杂度(C语言)》

文章目录 前言一、什么是空间复杂度?通俗理解: 二、空间复杂度的数学定义三、常见空间复杂度举例(含C语言代码)🔹 O(1):常数空间🔹 O(n):线性空间🔹 O(n^2):平…

智能合约安全审计平台——以太坊虚拟机安全沙箱

目录 以太坊虚拟机安全沙箱 —— 理论、设计与实战1. 引言2. 理论背景与安全原理2.1 以太坊虚拟机(EVM)概述2.2 安全沙箱的基本概念2.3 安全证明与形式化验证3. 系统架构与模块设计3.1 模块功能说明3.2 模块之间的数据流与安全性4. 安全性与密码学考量4.1 密码学保障在沙箱中…

【MCP教程】Claude Desktop 如何连接部署在远程的remote mcp server服务器(remote host)

前言 最近MCP特别火热,笔者自己也根据官方文档尝试了下。 官方文档给的Demo是在本地部署一个weather.py,然后用本地的Claude Desktop去访问该mcp服务器,从而完成工具的调用: 但是,问题来了,Claude Deskto…

多个路由器互通(静态路由)无单臂路由(简单版)

多个路由器互通(静态路由)无单臂路由(简单版) 开启端口并配ip地址 维护1 Router>en Router#conf t Router(config)#int g0/0 Router(config-if)#no shutdown Router(config-if)#ip address 192.168.10.254 255.255.255.0 Ro…

OpenCV 图形API(38)图像滤波-----Sobel 算子操作函数Sobel()

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::gapi::Sobel 函数是 OpenCV 的 G-API 模块中用于执行 Sobel 算子操作的一个函数,主要用于图像的边缘检测。Sobel 算子通过计算图…

windows系统安装驱动、cuda和cudnn

一、首先在自己的电脑里安装了nvidia的独立显卡 显卡的查找方式: CtrlShiftEsc打开任务管理器,点击性能,点击GPU 0查看显卡型号,如下图所示: 只要电脑中有nvidia的独立显卡,就可以暗转显卡驱动、cuda和cu…

嵌入式开发--STM32软件和硬件CRC的使用--续篇

本文是《嵌入式开发–STM32软件和硬件CRC的使用》的续篇,又踩到一个坑,发出来让大家避一下坑。 按照G0系列的设置,得出错误的结果 前文对应的是STM32G0系列,今天在用STM32G4系列时,按照前文的设置,用硬件…

【Git】git的简单使用

文章目录 1. 基础概念2. 简单使用2.1 git配置2.1.1 git的配置文件2.1.2 .gitignore文件 2.2 创建仓库2.2.1 创建本地仓库2.2.2 github创建远程仓库step1:github新建一个代码仓step2:创建密钥远程仓库相关指令2.2.3 本地仓库 关联 远程仓库 2.3 分支2.3.1…

[Web 安全] Web 信息收集 —— 信息收集流程

🌟 想系统化学习 Web 渗透?看看这个:[Web 安全] Web 安全攻防 学习手册 提示:本章不涉及任何具体信息收集技术,仅仅是讲解收集这些信息我能干啥,以及如何才能比较全面的收集信息。 0x01:信息收…

内部聊天软件,BeeWorks-安全的企业内部通讯软件

企业在享受数据便利的同时,如何保障企业数据安全已经成为无法回避的重要课题。BeeWorks作为一款专为企业设计的内部通讯软件,通过全链路的安全能力升维,为企业提供了一个安全、高效、便捷的沟通协作平台,全面保障企业数据安全。 …

应用篇02-镜头标定(上)

本节主要介绍相机的标定方法,包括其内、外参数的求解,以及如何使用HALCON标定助手实现标定。 计算机视觉——相机标定(Camera Calibration)_摄像机标定-CSDN博客 1. 原理 本节介绍与相机标定相关的理论知识,不一定全,可以参考相…

【UE5 C++】“ProceduralMeshComponent”的使用记录

效果 如下所示,通过“ProceduralMeshComponent”创建了一个自定义形状的Mesh,并且该Mesh包含碰撞信息,然后2s后更新Mesh形状。 步骤 1. 在“xxx.Build.cs”中引入“ProceduralMeshComponent”模块 2. 新建一个Actor类,这里命名为…