快速理解JS中的原型和原型链

快速理解JS中的原型和原型链

在我们学习JS的过程中,我们总会接触到一些词:"原型","原型链"。那么今天我就来带大家来学习学习原型和原型链的知识吧!

在开始之前,我们明确一下我们接下来想要学习的目标:

  • 什么是原型?
  • 什么是原型链?
  • 原型和原型链之间有什么关系?
  • 原型和原型链有什么作用?

原型

什么是原型呢?每个构造函数创建的对象都会在创建的时候自带(创建)一个 prototype 属性,这个属性是一个对象 ,这个对象就是我们要说的原型。是不是有点绕?来看下面这个例子:

javascript 复制代码
function Person(){}										

Person.prototype.name="zhangsan"
Person.prototype.sayName=function(){
	console.log("lisi")
}

const p1 = new Person()
console.log(p1.name)//zhangsan
console.log(p1.__proto__)// {name:"zhnagsan"}
console.log(p1.constructor)// [Function: Person]
console.log(Person.prototype===p1.__proto__)// true
console.log(Person.prototype.contructor===Person)// true

从这个例子可以看出,p1 是构造函数Peron()的实例对象,而实例对象通过__proto__和Person的prototype 属性连接起来了。看到这里,你是不是还是很疑惑,它们两个怎么就连接起来了?这就需要了解一下下面的知识点了:

  • 构造函数通常会有两个原型对象,一个是隐式原型__proto__,一个是显示原型prototype。而隐式原型是每一个对象都会拥有的。
  • 原型的一个作用大致可以理解成作为实例对象和构造函数之间的桥梁,但是请注意:实例对象与构造函数原型有直接联系,但是实例对象和构造函数之间没有直接联系!
  • 使用原型对象的还有一个好处是,在它上面定义的属性和方法可以被对象实例共享。也就是Person.prototype上面的属性和方法都会共享给实例对象,而且一个原型对象可以有多个实例的指向。
  • Person.prototype是 Person 构造函数的原型
  • p1.__proto__是实例对象 p1 的隐式原型,通过隐式原型可以访问对象的原型
  • 如上所述,构造函数有一个prototype属性引用其原型对象,而这个原型对象也有一个constructor属性,引用这个构造函数。也就是两者相互循环引用。

原型链

看完了上面内容,相信你已经对原型已经有了大概的了解,接下来我们进阶了解一下原型链 吧。看完上面的内容其实就很好理解原型链了,我们知道在使用实例对象的时候可以使用一些方法,像 toString、valueOf等,但是我们并没有在实例对象中定义这些方法,那这些方法是那里来的呢,实际上这些方法都是实际对象通过原型链到Object那里"拿"的。当我们调用一个对象中没有定义的方法时,JS 引擎会沿着原型链向上查找,直到找到该方法或达到原型链的顶端。(原型链也就是上图中右边一直向上"链条")。 这时候就会有人问:那么 JS 引擎是怎么利用原型链搜索的呢?请看下面的例子:

javascript 复制代码
function Peronson(){}
Person.prototype.name="zhangsan"

const p1=new Person();
console.log(p1.name)// zhangsan
p1.name="lisi"
console.log(p1.name)// lisi

JS 引擎在第一次打印的时候会问 p1 实例有 name 属性吗,答案是没有。然后继续搜索并问:p1 的原型有 name 属性吗?答案是有的,于是就返回了保存在原型上的这个 name 属性。第二次打印的时候 JS 引擎会问 p1 实例有 name 属性吗,答案是有的,于是就返回了保存在实例上的这个 name 属性。

实际上,在第二次打印的时候,p1原型上的 name 属性已经被 p1 实例的 name 属性给遮蔽了,也就是说虽然不会修改它,但会屏蔽它对原型上的同名属性。即时在实例上把这个属性设置为 null,也不会恢复它和原型的联系。不过使用 delete 操作符可以完全删除实例上的这个属性,从而让标识符解析过程能够继续搜索原型对象。

javascript 复制代码
function Peronson(){}
Person.prototype.name="zhangsan"

const p1=new Person();
console.log(p1.name)// zhangsan
p1.name="lisi"
console.log(p1.name)// lisi
delete p1.name
console.log(p1.name)// zhangsan

hasOwnProperty方法用于确定某个属性是在实例上还是在原型对象上,会在属性存在与掉用它的对象实例上时返回 true

javascript 复制代码
function Person(){}

const p1=new Person();
console.log(p1.name)// zhangsan,来自原型
console.log(p1.hasOwnProperty("name"))// false
p1.name="lisi"
console.log(p1.name)// lisi,来自实例
console.log(p1.hasOwnProperty("name"))// true

到这里,我相信大家已经可以回答文章开头所提出的几个问题了。如果大家有还有什么疑问或者有什么地方需要指正,欢迎指出。

相关推荐
Yuhano1 小时前
W4. RAG 让 Agent 拥有"外部记忆"
前端·aigc
用户30816998764851 小时前
gzip 和 br 压同一份 JSON:7.6MB 压到 175KB,差 3.8 倍
前端
掘金者阿豪1 小时前
电商视觉要被 Agent 重做了:一个平台跑通主图、详情页、实拍、复刻和视频
前端
爱勇宝2 小时前
《道德经》第 13 章:别让评价系统控制你的心
前端·后端·产品
掘金者阿豪2 小时前
集中式与分布式数据库怎么选?从架构原理到电科金仓的实践思考
前端·后端
codeejun2 小时前
每日一Go·MySQL-11、覆盖索引 & 回表原理
javascript·数据库·mysql
墨林陌2 小时前
AI 热点日报(2026-11-06):乌镇峰会闭幕发布全球开源AI倡议,腾讯混元Hy4发布即开源
前端
用户298698530143 小时前
React 前端将 Excel 工作表导出为图片的技术实践
javascript·react.js·excel
亿元程序员3 小时前
8年游戏主程从公司毕业了,能干些啥?
前端
Cosolar3 小时前
极简智库(MiniDocs):docsify、VitePress、Notion 等知识库搭建服务的完美替代
前端·后端·架构