快速理解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

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

相关推荐
rzl0216 分钟前
java web5(黑马)
java·开发语言·前端
Amy.Wang17 分钟前
前端如何实现电子签名
前端·javascript·html5
海天胜景19 分钟前
vue3 el-table 行筛选 设置为单选
javascript·vue.js·elementui
今天又在摸鱼20 分钟前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿21 分钟前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再24 分钟前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref
jingling55528 分钟前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架
拾光拾趣录33 分钟前
CSS 深入解析:提升网页样式技巧与常见问题解决方案
前端·css
莫空000034 分钟前
深入理解JavaScript属性描述符:从数据属性到存取器属性
前端·面试
guojl35 分钟前
深度剖析Kafka读写机制
前端