快速理解JS中的原型和原型链
在我们学习JS的过程中,我们总会接触到一些词:“原型”,“原型链”。那么今天我就来带大家来学习学习原型和原型链的知识吧!
在开始之前,我们明确一下我们接下来想要学习的目标:
- 什么是原型?
- 什么是原型链?
- 原型和原型链之间有什么关系?
- 原型和原型链有什么作用?
原型
什么是原型呢?每个构造函数创建的对象都会在创建的时候自带(创建)一个 prototype
属性,这个属性是一个对象,这个对象就是我们要说的原型。是不是有点绕?来看下面这个例子:
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 引擎会沿着原型链向上查找,直到找到该方法或达到原型链的顶端。
所以原型链也就是上图中右边一直向上“链条"。
到这里,我相信大家已经可以回答文章开头所提出的几个问题了。