深入剖析JavaScript的原型及原型链

news2024/10/7 16:26:27

什么是JavaScript的原型?

原型是函数上的一个属性,它定义了构造函数制造的对象的公共祖先

原型的主要作用在于实现对象之间的属性和方法共享,从而节省内存空间,提高代码的效率

  • 我们通过一段代码来接讲解,通过购买小米su7这个例子讲解

    • 首先我们创建一个function Car来作为车的构造函数
function Car(color, owner) {
this.name = 'su7'
this.lang = 5000
this.height = 1400
this.color = color
this.owner = owner
}

当使用 new Car(...) 来创建新的实例时,每个实例都会具有 namelangheightcolorowner 这些属性。其中 colorowner 的值会根据创建实例时传递的参数来确定,而 namelangheight 的值则是固定的。

接下来我们就去购买小米汽车了

let tian = new Car('black', 'tiantian')

这里我们给tiantian购买了一辆su7,在构造su7的时候,车子的name,lang,height是不变的,无论是谁来购买,这三个数据是不会变的,只有主人和颜色是可以变的,但是每次购买su7的时候,还是会重新创建一份关于name,lang,height的数据,这样就造成了内存的浪费,降低了代码的效率

所以我们的代码可以改造为

Car.prototype.name = 'su7'
Car.prototype.lang = 5000
Car.prototype.height = 1400
function Car(color, owner) {
    // this.name = 'su7'
    // this.lang = 5000
    // this.height = 1400
    this.color = color
    this.owner = owner
}

let tian = new Car('black', 'tiantian')
console.log(tian);
console.log(tian.name); //隐式具有,也就是继承了

代码通过在 Car 的原型对象 Car.prototype 上定义了 namelangheight 属性。

当创建 tian 这个 Car 的实例时,虽然在构造函数内部没有直接为实例设置 namelangheight 属性,实例仍然可以访问到在原型对象上定义的这些属性。

所以当打印 tian 时,会显示出包含从原型继承的属性以及在构造函数中设置的 colorowner 属性的对象。而打印 tian.name 时,能够获取到在原型上定义的 'su7'

image.png

这样就实现了name,lang,height的数据共享,节约了内存

这里我们已经对原型有一个初步的认识了,接下来我们继续讲解什么是prototype属性

Car.prototype.product = "xiaomi"

function Car() {
    this.name = "su7"
}

var car = new Car();

console.log(car);
console.log(car.name);
console.log(car.product);

这段代码的执行结果为

image.png

现在如果我们想修改product的值,可以直接修改吗?

car.product = "iphone"

现在添加这段代码,我们可以看到的运行效果为

image.png

很显然并不能通过这种方式去修改prototype里面的product

这里我们就明白了一个重要的结论:

  • 实例对象可以修改显示继承到的属性
  • 实例对象无法修改隐式继承到的属性(原型上的属性)
  • 实例对象无法给原型新增属性
  • 实例对象无法删除原型上的属性

对象里面到底有什么?

我们将这段代码放在浏览器运行

<script>
  function A() {}

  let a = new A();

  console.log(a);
</script>

你可以看到这样的结果

image.png

可以看到在A{}里面有[[Prototype]][[Prototype]]为对象的原型

注:在谷歌浏览器显示为[[Prototype]],别的浏览器可能显示为__proto__

我们继续修改代码

<script>
  function A() {}

  let a = new A();

  console.log(A.prototype);
  console.log(a.__proto__);
</script>

这段代码的结果为

image.png

结果显而易见,对象的原型 === 它的构造函数的原型

在对象的原型又叫隐式原型,函数的原型又叫显示原型,所以结论可以改为

对象的隐式原型 === 创建它的构造函数的显式原型

这里可以理解为对象用自己来继承函数里的属性,对象用它的原型承接函数的原型的熟悉

对象可以访问到构造函数的显式原型属性,为什么?

回到最初的购买su7

Car.prototype.product = "xiaomi"

function Car() {
    this.name = "su7"
}

var car = new Car();

console.log(car);
console.log(car.name);
console.log(car.product);

现在我们来讨论为什么console.log(car.product);可以打印出结果?

其实V8引擎在执行这段代码时,首先会去car的显示属性里面寻找,然后再去隐式原型里面找,然后隐式原型又相当于其构造函数的显示原型,这便是原型链

原型链

通过以下代码,我们来讲解一下原型链

<script>
  function A() {}

  let a = new A();

  console.log(a);
</script>

我们通过不断的展开对象的__proto__,我们就能够发现一个事情

动画.gif

从这里我们可以看出来两个信息:

  • a.__proto__ === A.prototype
  • A.prototype.__proto__ === Object.prototype

为了方便理解,我们作图讲解

image.png

在 JavaScript 中,Object.prototype.__proto__ 的值为 nullObject.prototype 处于原型链的顶端,没有更高层次的原型

除了 Object 构造函数,几乎所有构造函数的原型对象最终都会通过原型链追溯到 Object.prototype,以继承一些通用的方法和属性,比如 toStringvalueOf

我们通过一个小demo更加直观的感受一下原型链

function GrandFather() {
  this.age = 60;
  this.like = 'drink';
}

Father.prototype = new GrandFather();
function Father() {
  this.age = 40;
  this.fortune = 1000;
}

Son.prototype = new Father();
function Son() {
  this.age = 20;
}

let son = new Son();

console.log(son.age);
console.log(son.fortune);
console.log(son.like);

首先定义了 GrandFather 构造函数,并设置了属性 agelike

然后将 Father 的原型对象设置为 GrandFather 的一个实例,接着定义了 Father 构造函数,设置了属性 agefortune

之后将 Son 的原型对象设置为 Father 的一个实例,再定义了 Son 构造函数,设置了属性 age

我们可以看到结果为:

image.png

console.log(son.age) 输出 20 ,因为实例自身的 age 属性会覆盖原型链上的同名属性。

console.log(son.fortune) 输出 1000 ,这是从原型 Father 继承的

console.log(son.like) 输出 drink ,这也是从原型链上的 GrandFather 继承的

这里我们可以得出一个结论:

js引擎在查找属性时,会沿着原型链查找。即对象的隐式原型向上查找,找不到就沿着隐式原型的隐式原型继续查找,直到找到Object.prototype._proto__,如果没找到就返回undefined。null为止

网易面试题:世界上所有的对象都有隐式原型吗?

答案是否定的

有一种写法是没有隐式原型的

首先我们来看这段代码

let a = {
    name:'tom'
}

let obj = Object.create(a)

console.log(obj)

这段代码的结果为

image.png

这里我们可以看出来这个方法的作用为创建一个新对象,让新对象隐式的继承a的属性

那如果我们使用let obj = Object.create(null)呢?

直接公布结果:

image.png

这样创建出来的对象是没有隐式原型的

总结

本文深度的解析了原型及原型链,从各个角度出发结合代码去分析过程原理以及结果,并结合面试题深入剖析知识点

相信看到这里的你一定会有所收获的!!!!

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

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

相关文章

掉了两根头发后,我悟了!vue3的scoped原来是这样避免样式污染(上)

前言 众所周知&#xff0c;在vue中使用scoped可以避免父组件的样式渗透到子组件中。使用了scoped后会给html增加自定义属性data-v-x&#xff0c;同时会给组件内CSS选择器添加对应的属性选择器[data-v-x]。这篇我们来讲讲vue是如何给CSS选择器添加对应的属性选择器[data-v-x]。…

OpenFAST软件中linux-gnu,linux-intel,macos-gnu,vtk,windows-intel文件的作用

在OpenFAST中&#xff0c;5MW_Land_DLL_WTurb目录下的这五个文件夹分别有不同的用途&#xff0c;主要是为了支持不同操作系统和平台的编译和仿真工作。以下是每个文件夹的总结及其作用&#xff1a; linux-gnu 作用&#xff1a;包含用于GNU编译器套件&#xff08;GCC&#xff09…

私有化部署 Dify 并快速搭建 AI 应用

Dify介绍 Dify 是一个开源的 LLM 应用开发平台。其直观的界面结合了 AI 工作流、RAG 管道、Agent、模型管理、可观测性功能等&#xff0c;让您可以快速从原型到生产。以下是其核心功能列表&#xff1a; 1. 工作流: 在画布上构建和测试功能强大的 AI 工作流程&#xff0c;利用…

大数据之路 读书笔记 Day2

大数据之路 读书笔记 Day2 日志采集——浏览器的页面采集 一、分类 #mermaid-svg-ar0WySJJTNk7KvqN {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ar0WySJJTNk7KvqN .error-icon{fill:#552222;}#mermaid-svg-ar0…

keil仿真,查看函数执行时间和执行次数

Execution Profiler执行档案器 The Execution Profiler records timing and execution statistics about instructions for the complete program code. To view the values in the Editor or Disassembly Window, use Show Time or Show Calls from the menu Debug — Executi…

IND83081芯片介绍(一)

一、芯片介绍 IND83081是indiemicro推出的一款高性能的汽车矩阵LED照明控制器&#xff0c;集成了四个子模块&#xff0c;每个子模块包含三个串联的MOSFET开关&#xff0c;每个开关均可通过12位PWM内部信号控制&#xff0c;可配置的上升和下降速率及相位移以实现精确控制&#x…

昇思25天学习打卡营第1天|快速入门-Mnist手写数字识别

学习目标&#xff1a;熟练掌握MindSpore使用方法 学习心得体会&#xff0c;记录时间 了解MindSpore总体架构 学会使用MindSpore 简单应用时间-手写数字识别 一、MindSpore总体架构 华为MindSpore为全场景深度学习框架&#xff0c;开发高效&#xff0c;全场景统一部署特点。 …

如何ubuntu安装wine/deep-wine运行exe程序(包括安装QQ/微信/钉钉)

1.失败的方法&#xff1a; ubuntu22.04尝试下面这个链接方法没有成功&#xff0c; ubuntu22.04安装wine9.0_ubuntu 22.04 wine-CSDN博客 上面链接里面也提供了wine官方方法&#xff0c;链接如下&#xff1a;https://wiki.winehq.org/Ubuntu_zhcn 但是运行最后一个命令时候报…

win10 C:\Users\Administrator

win10 C:\Users\Administrator C:\Users\Administrator\Documents\ C:\Users\Administrator\Pictures C:\Users\Administrator\Favorites C:\Users\Administrator\Links C:\Users\Administrator\Videos

【C++】————内存管理

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年6月26日 一、C内存分布 我们先来看一串代码&#xff1a; int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] …

电脑怎么设置锁屏密码?这3个方法你知道吗

在日常生活中&#xff0c;电脑已成为我们工作和娱乐的重要工具。为了保护个人信息和数据安全&#xff0c;设置锁屏密码是必不可少的一步。通过设置锁屏密码&#xff0c;您可以有效防止未经授权的访问&#xff0c;确保电脑上的隐私和数据不被泄露。本文将详细介绍电脑怎么设置锁…

STM32_hal_STM32Cude_实现RT—Thread系统

1stm32cude下载系统 1.-2下载显示绿色的为下载成功 2为项目导入系统---点击如下选项 2-1选中如下 意思为 kemel 系统内核 shell shell的实现 device 设备 2-2可以看到项目选项中多了如图选项 3实现led闪烁 3-1 定义两个引脚用于控制led 3-2选择时钟源 3-3更改延迟函数…

Planned independent reguirement can only be maintained via the network

背景&#xff1a;用户上线ps系统&#xff0c;物料用策略70跑需求 但是因为通用料被改了策略&#xff0c;改成其他的了&#xff0c;影响到计划独立需求了。 如果用户不需要了哪个料就会把数量改为0&#xff0c;或者直接删掉物料。之前建议是改成0&#xff0c;这样还有个记录在…

【Python机器学习】交互特征与多项式特征

对于线性模型来说&#xff0c;想要丰富特征&#xff0c;还有一种方法是添加原始数据的交互特征和多项式特征。这种特征工程通常用于统计建模&#xff0c;但也经常用于实际的机器学习应用中。 交互特征 上一篇的例子里&#xff0c;线性模型对wave数据集的的每个箱子都学到一个…

基于稀疏矩阵方法的剪枝压缩模型方案总结

1.简介 1.1目的 在过去的一段时间里&#xff0c;对基于剪枝的模型压缩的算法进行了一系列的实现和实验&#xff0c;特别有引入的稀疏矩阵的方法实现了对模型大小的压缩&#xff0c;以及在部分环节中实现了模型前向算法的加速效果&#xff0c;但是总体上模型加速效果不理想。所…

从零到一打造自己的大模型:模型训练

前言 最近看了很多大模型&#xff0c;也使用了很多大模型。对于大模型理论似乎很了解&#xff0c;但是好像又缺点什么&#xff0c;思来想去决定自己动手实现一个 toy 级别的模型&#xff0c;在实践中加深对大语言模型的理解。 在这个系列的文章中&#xff0c;我将通过亲手实践…

【面试题】Spring面试题

目录 Spring Framework 中有多少个模块&#xff0c;它们分别是什么&#xff1f;Spring框架的设计目标、设计理念&#xff1f;核心是什么&#xff1f;Spring框架中都用到了哪些设计模式&#xff1f;Spring的核心机制是什么&#xff1f;什么是Spring IOC容器&#xff1f;什么是依…

竞赛选题 python区块链实现 - proof of work工作量证明共识算法

文章目录 0 前言1 区块链基础1.1 比特币内部结构1.2 实现的区块链数据结构1.3 注意点1.4 区块链的核心-工作量证明算法1.4.1 拜占庭将军问题1.4.2 解决办法1.4.3 代码实现 2 快速实现一个区块链2.1 什么是区块链2.2 一个完整的快包含什么2.3 什么是挖矿2.4 工作量证明算法&…

鸿蒙面试心得

自疫情过后&#xff0c;java和web前端都进入了冰河时代。年龄、薪资、学历都成了找工作路上躲不开的门槛。 年龄太大pass 薪资要高了pass 学历大专pass 好多好多pass 找工作的路上明明阳关普照&#xff0c;却有一种凄凄惨惨戚戚说不清道不明的“优雅”意境。 如何破局&am…

修复:cannot execute binary file --- ppc64le 系统架构

前言&#xff1a; 修复node_exporter,引用pprof包&#xff0c;对源码编译后在 Linux 系统下执行程序运行时&#xff0c;发生了报错&#xff0c;报错信息&#xff1a;cannot execute binary file: Exec format error。 开始以为编译有问题&#xff0c;检查发现&#xff1b;该l…