〖大前端 - 基础入门三大核心之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,一经查实,立即删除!

相关文章

Android之Apk相关操作,以32位或64位运行apk,区分apk支持CPU架构的办法

一、以32位或64位安装运行apk 连接手机,准备好apk文件,打开cmd 32位: adb install --abi armeabi-v7a 打包的Apk路径64位 adb install --abi arm64-v8a 打包的apk路径二、区分32位和64位包 参考链接: https://blog.51cto.com/…

JavaScript算法46- 最长连续序列(leetCode:128middle)

128. 最长连续序列 一、题目 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 输入:nums [100,4,200,1,3,2] 输出…

曹操出行集成:无代码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.其…

携程英语测评(已offer)

携程英语测评大概有这么几种题型:读出屏幕上的句子,读出他说过一遍的句子,长对话听力,给题目临场说一段小作文,语法语义判断。大概就是这五个部分吧,我这里主要介绍一下临场作文题 临场作文我搜集了下网上…

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 …

PHP中的依赖注入是怎样的?

依赖注入(Dependency Injection,DI)是一种设计模式,它用于解耦组件之间的依赖关系,提高代码的可维护性、可测试性和灵活性。在 PHP 中,依赖注入通常通过构造函数注入、方法注入或属性注入来实现。 以下是依…

微服务组件Sentinel的学习(1)

Sentinel学习笔记(1) Sentinel基本概念Sentinel功能和设计理念流量控制熔断降级系统负载保护 Sentinel基本概念 资源 资源是Sentinel的关键概念。它可以是 ava应用程序中的任何内容,例如,由应用程序提供的服务,或由应…

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

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

Elasticsearch 8.10之前同义词最佳实践

1、同义词在搜索引擎领域用途 同义词在搜索引擎领域的用途可概括如下: 增强搜索的准确性——当用户输入一个关键词时,可能与他们实际意图相关的文档使用了一个不同的关键词或短语。同义词允许搜索引擎理解和识别这些情况,返回更准确的结果。如:“遥遥领先”和“华为Meta60…

QT学习(20):QTcpSocket和QAbstractSocket

目录 QAbstractSocket建立连接的函数和信号阻塞功能QTcpSocket QAbstractSocketPrivateQAbstractSocketEngine和QNativeSocketEngine QAbstractSocket QAbstractSocket 是QTcpSocket和QUdpSocket的基类,并且包含这两个类的所有通用功能。如果需要套接字&#xff0c…

WT588F02B-8S语音芯片:灵活应用的语音播放利器,实现多重优势

在智能语音交互领域,唯创知音WT588F02B-8S可重复擦写(Flash型)语音芯片声音播放提示IC凭借其出色的特性,为用户提供了更灵活、高效的语音解决方案。本文将聚焦于该芯片的应用优势,包括实现用户自主更新语音文件、节约打…

WTN6xxx系列OTP语音芯片:智能语音解决方案的可靠之选

在智能语音交互领域,唯创知音的WTN6xxx系列OTP语音芯片以其独特的特性成为声音播放提示IC的可靠之选。本文将深入探讨WTN6xxx系列OTP语音芯片的应用优势,展示其在各个方面的卓越性能。 一、低成本、高性能 1.经济实惠: WTN6xxx系列OTP语音芯…

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

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

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

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