在理解 JavaScript 中的对象和继承时,原型链是一个至关重要的概念。JavaScript 是一种基于原型的语言,这意味着对象可以直接从其他对象继承属性和方法。
每个 JavaScript 对象都有一个指向其原型的链接,这个链接是一个指针,它指向了创建该对象的构造函数的原型对象。这个原型对象也有自己的原型,这样就形成了一个链,直到最终指向 null
为止。
当访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 会沿着原型链向上查找,直到找到匹配的属性或方法,或者到达原型链的末尾(null
)。
通过利用原型链,我们可以实现对象之间的继承,这是 JavaScript 中实现面向对象编程的基础之一。
那么具体是如何实现的呢,且看下面的示例图
上图中Foo、Object、Function都是构造类,规范类的函数名称首字母大写,类有自己的原型也就是prototype,而每个prototype都有一个construtor指向类本身。
在new Foo() 创建f1、f2实例的时候js底层是这样执行的
- 创建一个空对象
- 将这个空对象的原型指向Foo的原型对象
- 将Foo中的this指向这个空对象
- 执行Foo内部的代码
- 返回这个对象
至此就创建出了一个Foo的实例,这个实例拥有Foo的原型方法,也有了Foo类this.attr的属性,f1和f2的原型指向的是同一个原型对象也就是Foo的prototype,而属性attr又是自身相互独立不互相干扰的。
__proto__ 为原型,prototype为原型对象
我们看到Foo的原型和Object的原型以及Function自己的原型都指向了Function的原型对象,这是为什么呢?在js中是这样解释的,任何函数都是被Function所创造的包括Function自己,而Foo和Object本身就是一个函数,所以是Function的实例,所以他们的原型指向了Function的原型对象。
任何对象都是被Object所创造的,上图中不管o1和o2是Object的实例,几乎任何类的原型也是如此,所以我们看到o1、o2的原型和Fcuntion.prototype的原型以及Foo.prototype的原型都指向了Object的原型对象,Object的原型最终继承自null。
总结几点
- 除Function以外的任何构造函数和函数都是Function的实例
- 除Object以外的几乎任何对象都是Object实例
- 每个实例的原型都指向创建它的构造类的原型对象
- 任何原型对象都可通过原型实现继承也就形成了原型链