快速理解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__Personprototype 属性连接起来了。看到这里,你是不是还是很疑惑,它们两个怎么就连接起来了?这就需要了解一下下面的知识点了:

  • 构造函数通常会有两个原型对象,一个是隐式原型__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

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

相关推荐
星星在线26 分钟前
MusicFree:一个「All in One」的个人音乐服务器,让听歌回归简单
前端·后端
IT_陈寒1 小时前
Redis的SETNX并发问题让我加了三天班
前端·人工智能·后端
demo007x2 小时前
Docling 文档转换以及技术架构分析
前端·后端·程序员
京东云开发者2 小时前
京东市民服务又“上新”!这次是黑龙江“龙易办”
前端
袋鱼不重3 小时前
我的神奇同事,AI 用多了居然写了个 Open In Codex
前端·后端·ai编程
竹林8183 小时前
Web3表单签名验证:我用 wagmi 和 ethers 给 DApp 加了一个“免密登录”,踩坑记录全在这了
javascript
用户6990304848753 小时前
try catch使用场景 处理同步代码错误兼容用的
javascript·uni-app
雪碧聊技术3 小时前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
Fireworks3 小时前
深入vue3源码解读 -- 1、响应式的基础概念
前端
程序员黑豆3 小时前
JDK 下载安装与配置详细教程
java·前端·ai编程