〖大前端 - 基础入门三大核心之JS篇(54)〗- 原型和原型链

  • 说明:该文属于 大前端全栈架构白宝书专栏,目前阶段免费如需要项目实战或者是体系化资源,文末名片加V!
  • 作者:哈哥撩编程,十余年工作经验, 从事过全栈研发、产品经理等工作,目前在公司担任研发部门CTO。
  • 荣誉:2022年度博客之星Top4、2023年度超级个体得主、谷歌与亚马逊开发者大会特约speaker全栈领域优质创作者

  • 🏆 白宝书系列
    • 🏅 启示录 - 攻城狮的自我修养
    • 🏅 Python全栈白宝书
    • 🏅 ChatGPT实践指南白宝书
    • 🏅 产品思维训练白宝书
    • 🏅 全域运营实战白宝书
    • 🏅 大前端全栈架构白宝书


文章目录

  • ⭐ 原型和原型链
  • ⭐ hasOwnProperty方法和in运算符
  • ⭐ 在prototype上添加方法

⭐ 原型和原型链

原型和原型链是实现JavaScript继承的主要机制,许多面向对象的特性,如类的方法继承等,都是基于原型和原型链的。

在JavaScript中,每个对象都有一个特殊的内部属性[[Prototype]],它是对象的原型。原型也就是其他对象的引用,每个对象都从原型“继承”属性。

原型链是通过同样的[[Prototype]]属性链接起来的,形成了一条链状结构。“原型链”就是对象通过[[Prototype]]属性引用其他对象,然后通过这些对象再引用其他对象,如此形成的一条链状结构。

当我们访问对象的某个属性时,JavaScript会首先在该对象自身的属性中查找,如果没有找到,那么JavaScript会在该对象的[[Prototype]]原型对象中查找,如果还是没有找到,那么JavaScript就会继续在原型的原型中查找,即在原型链上向上查找,直到找到属性或者查找到null(原型链的末端)为止。如果在原型链的最顶端也没有找到这个属性,那么就会返回undefined。这就是原型链在JavaScript属性查找中的作用。

prototype,原型。任何函数都有prototype属性。

prototype属性值是个对象,它默认拥有constructor属性指回函数

image-20230619151013992

下面我们来敲一个例子证明prototype这个属性的存在,再看一下它的具体功能:

function sum(a, b) {return a + b;
}console.log(sum.prototype);
console.log(typeof sum.prototype);  // object
console.log(sum.prototype.constructor);
console.log(sum.prototype.constructor === sum);   // true;证明protoype的constructor属性指向原函数

image-20230712151012627

  • 对于普通函数来说,prototype属性没有任何用处,而构造函数的prototype属性非常有用
  • 构造函数的prototype属性是它的实例的原型

下面我们看下一张图来解释什么叫做“构造函数的prototype属性是它的实例的原型”

image-20230712152625260

乍一看这个图并不能理解其中的含义,只是知道构造函数、构造函数的prototype属性和构造函数的实例三者之间存在一种“三角”关系。我们来敲一下代码,从代码维度来理解这三者的关系:

function People(name, age, sex) {this.name = name;this.age = age;this.sex = sex;
}
// 实例化
var xiaoming = new People('小明', 12, '男');
// 测试三角关系是否存在
console.log(xiaoming.__proto__ === People.prototype);  // true

image-20230712162818967

上面的代码只是证明了构造函数、构造函数的prototype属性和构造函数的实例存在的这种三角关系,但这个关系到底在编写代码中有什么作用呢?答案是,我们可以利用这个三角关系实现“原型链查找”。

JavaScript规定:实例可以打点访问它的原型的属性和方法,这被成为“原型链查找”

示例代码:

function People(name, age, sex) {this.name = name;this.age = age;this.sex = sex;
}
// 往原型上添加nationality属性
People.prototype.nationality = '中国';
var xiaoming = new People('小明', 12, '男');
console.log(xiaoming.nationality);
console.log(xiaoming);

image-20230713101527969

当实例化对象打点调用某个属性时,系统发现它本身没有这个属性,此时并不会报错,而是回去查找它的“原型”上有没有这个属性,如果有,则会把这个属性输出。

下面把上面的例子延伸一下,我们在People这个构造函数再实例化一个对象,这个对象本身就有nationality属性,那我们用这个对象打点调用nationality属性时,会返回什么呢?示例代码:

function People(name, age, sex) {this.name = name;this.age = age;this.sex = sex;
}
// 往原型上添加nationality属性
People.prototype.nationality = '中国';// 实例化
var xiaoming = new People('小明', 12, '男');
var tom = new People('Tom', 11, '男');
tom.nationality = '美国';console.log(xiaoming.nationality);
console.log(xiaoming);
console.log(tom.nationality);  // 美国

image-20230713102722477

可以看到,如果这个实例化对象本身就有nationality属性时,打点会直接访问到这个属性,而不是去访问原型上的nationality属性,这个就是原型链的遮蔽效应

⭐ hasOwnProperty方法和in运算符

hasOwnProperty方法可以检查对象是否真正“自己拥有”某属性或者方法

和hasOwnProperty方法有些类似的是in运算符:

in运算符只能检查某个属性或方法是否可以被对象访问,不能检查是否是自己的属性或方法

示例代码:

function People(name, age, sex) {this.name = name;this.age = age;this.sex = sex;
}
// 往原型上添加nationality属性
People.prototype.nationality = '中国';// 实例化
var xiaoming = new People('小明', 12, '男');console.log(xiaoming.hasOwnProperty('name'));   // true
console.log(xiaoming.hasOwnProperty('age'));   // true
console.log(xiaoming.hasOwnProperty('sex'));   // true
console.log(xiaoming.hasOwnProperty('nationality'));   // falseconsole.log('name' in xiaoming);   // true
console.log('age' in xiaoming);   // true
console.log('sex' in xiaoming);   // true
console.log('nationality' in xiaoming);   // true

image-20230713104250772

⭐ 在prototype上添加方法

之前在实例化对象时,是直接往实例化对象上添加方法,实例化多少个对象,就会在内存中创建多少个方法,这些方法虽然名字相同,但在内存中的地址是不同的,敲一段代码来验证一下:

function People(name) {this.name = name;this.sayHello = function () {};
}
// 实例化
var xiaoming = new People('xiaoming');
var xiaobai = new People('xiaobai');
var xiaohei = new People('xiaohei');console.log(xiaoming.sayHello === xiaobai.sayHello);

image-20230714103610250

把方法直接添加到实例身上的缺点:每个实例和每个实例的方法函数都是内存中不同的函数,造成了内存的浪费

如果把方法添加到prototype身上,就可以避免这个问题,将上面的例子改造后代码如下:

function People(name) {this.name = name;}
//把方法写到原型上
People.prototype.sayHello = function () {console.log('您好,我是' + this.name);
}
// 实例化
var xiaoming = new People('xiaoming');
var xiaobai = new People('xiaobai');
var xiaohei = new People('xiaohei');xiaoming.sayHello();
xiaobai.sayHello();
xiaohei.sayHello();
console.log(xiaoming.sayHello === xiaobai.sayHello);

image-20230714111236033

把方法写在原型上是聪明有效的避免内存重复占用的方式,我们一定要习惯使用这种写法。

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

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

相关文章

曹操出行集成:无代码API连接广告推广与用户运营

曹操出行集成的必要性 随着科技的不断进步,无代码API集成已经成为企业提升效率、优化营销策略的重要手段。对于新能源汽车共享服务领导者曹操出行而言,将其服务集成至企业营销系统中,不仅可以提升客户体验,还能加强品牌的市场竞争…

微信小程序 全局共享数据 mobx

前言 全局数据共享(又叫做:状态管理)是为了解决组件之间数据共享的问题。开发中常用的全局数据共享方案有:Vuex、Redux、MobX 等。 一. 安装 npm install --save mobx-miniprogram4.13.2 mobx-miniprogram-bindings2.1.5 安装完…

基于主动安全的AIGC数据安全建设

面对AIGC带来的数据安全新问题,是不是就应该一刀切禁止AIGC的研究利用呢?答案是否定的。要发展AIGC,也要主动积极地对AIGC的数据安全进行建设。让AIGC更加安全、可靠的为用户服务。为达到此目的,应该从三个方面来开展AIGC的数据安…

【WebRTC】用WebRTC做即时视频聊天应用

【配套项目源码】 打开即用,设置一个免费的Agora账户就可以实现视频电话。非常好的WebRTC学习和应用项目。 用VSCode打开即可。 https://download.csdn.net/download/weixin_41697242/88630069 【什么是WebRTC?】 WebRTC是一套基于JS的API,能够建立端对端的直接通信,实…

后端接口开发-web前台请求接口对后台数据库增删改查-实例

一、后端接口开发的逻辑是: 1.Application项目启动 2.前台接口Url请求后台 3.Controller控制拿到前台请求参数,传递给中间组件Service 4.Service调用Mapper.java 5. mapper.java映射到mapper.xml中的mybatis语句,类似Sql语句操作数据库 6.其…

GDPU 数据结构 天码行空14

实验十四 查找算法的实现 一、【实验目的】 1、掌握顺序排序,二叉排序树的基本概念 2、掌握顺序排序,二叉排序树的基本算法(查找算法、插入算法、删除算法) 3、理解并掌握二叉排序数查找的平均查找长度。 二、【实验内容】 …

群晖(Synology)云备份的方案是什么

群晖云备份方案就是在本地的 NAS 如果出现问题,或者必须需要重做整列的时候,保证数据不丢失。 当然,这些是针对有价值的数据,如果只是电影或者不是自己的拍摄素材文件,其实可以不使用云备份方案,因为毕竟云…

Ubuntu如何安装KVM

环境: 联想E14笔记本 Ubuntu20.04 问题描述: Ubuntu如何安装KVM 解决方案: 1.验证CPU是否支持硬件虚拟化 rootst-ThinkPad-E14:~# grep -Eoc (vmx|svm) /proc/cpuinfo 162.检查 VT 是否在 BIOS 中启用 安装 apt install cpu-checker …

stm32F407-GPIO的使用——点亮LED并且讲解各个寄存器

stm32F407-GPIO的使用——点亮LED并且讲解各个寄存器 本文为stm32GPIO的介绍与使用,例子是简单的LED点亮。 一、 GPIO GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说, 就是一些引脚,可…

AGI魔盒,会放出冥王PLUTO还是阿童木?

人机共生,是科幻作品永恒的主题。其中,《冥王PLUTO》可能是最早探讨人类与机器人如何在冲突中共存的漫画作品。 如果说阿童木是人机共生的“和平使者”,启蒙了几代人对机器人的信任和热爱,那么冥王PLUTO就是阿童木的反面,一个心怀…

基于ssm网络安全宣传网站设计论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本网络安全宣传网站就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息…

2023-12-14 使用Qt画一条曲线(AI辅助)

点击 <C 语言编程核心突破> 快速C语言入门 使用Qt画一条曲线 前言一、Qchart简介二、代码总结 前言 要解决问题: 有一个函数, 生成一些点, 想画一条曲线. 想到的思路: 这个用Qchart比较简单. 其它的补充: 需要稍许配置 一、Qchart简介 QChart是Qt中的一个图表控件&a…

记录 | mac打开终端时报错:login: /opt/homebrew/bin/zsh: No such file or directory [进程已完成]

mac打开终端时报错&#xff1a;login: /opt/homebrew/bin/zsh: No such file or directory [进程已完成]&#xff0c;导致终端没有办法使用的情况 说明 zsh 没有安装或者是安装路径不对 可以看看 /bin 下有没有 zsh&#xff0c;若没有&#xff0c;肯定是有 bash 那就把终端默…

三层交换机原理与配置

文章目录 三层交换机原理与配置一、三层交换技术概述二、传统的 MLS三、基于CEF 的MLS1、转发信息库&#xff08;FIB&#xff09;2、邻接关系表3、工作原理&#xff1a; 四、三层交换机的配置1、三层交换机配置命令2、三层交换机配置步骤 三层交换机原理与配置 一、三层交换技…

【Hadoop】

Hadoop是一个开源的分布式离线数据处理框架&#xff0c;底层是用Java语言编写的&#xff0c;包含了HDFS、MapReduce、Yarn三大部分。 组件配置文件启动进程备注Hadoop HDFS需修改需启动 NameNode(NN)作为主节点 DataNode(DN)作为从节点 SecondaryNameNode(SNN)主节点辅助分…

如何学习Kubernetes,学习K8S入门教程

学习 Kubernetes&#xff08;K8s&#xff09;确实不容易 你的硬件资源有限时&#xff0c;不过别担心&#xff0c;我帮你理清思路&#xff0c;让你在学习 K8s 的路上更加从容。 1、资源限制下的学习方法 当硬件资源有限时&#xff0c;一个好的选择是使用云服务提供的免费层或者…

✺ch2——OpenGL图像管线

目录 基于C图形应用&#xff06;管线概览OpenGL类型第一个C/OpenGL应用程序◍API (1) GLSL类型着色器——画一个点的程序◍API (2)◍API (3) 栅格化像素操作——Z-buffer算法检测 OpenGL 和 GLSL 错误◍API (4) 从顶点来构建一个三角形场景动画◍API (5) OpenGL某些方面的数值—…

ArcGIS导入excel中的经纬度信息,绘制矢量

1.首先整理坐标信息 2.其次转成2003格式的excel文件 3.导入arcgis&#xff0c;点击右键添加excel数据 4.显示xy数据 5.显示经度和纬度信息 6&#xff1a;点击【地理坐标系】->【World】->【WGS 1984】->【确定】 7.投影带的确定方式&#xff1a; 因为自己一直…

spring 笔记五 SpringMVC的数据响应

文章目录 SpringMVC的数据响应SpringMVC的数据响应方式回写数据 SpringMVC的数据响应 SpringMVC的数据响应方式 页面跳转 直接返回字符串通过ModelAndView对象返回 回写数据 直接返回字符串返回对象或集合 返回字符串形式 直接返回字符串&#xff1a;此种方式会将返回的字符…

腾讯云Elasticsearch Service产品体验

基本介绍 产品概述 腾讯云 Elasticsearch Service&#xff08;ES&#xff09;是云端全托管海量数据检索分析服务&#xff0c;拥有高性能自研内核&#xff0c;集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群&#xff0c;也支持免运维、自动弹性、按需…