写在前面:本帖用于复习原型链,验证阶段性的学习成果,欢迎大家批评指正!
原型链的设计是为了将公共方法抽离,放在原型对象上,并且使用工厂函数的形式,为每个实例进行初始化的“装饰作用”,私以为可以用组合继承的思想来解释原型链。这样既有原型的内存空间存放公共数据和方法,也有每个实例独有的内存空间,存放特有的数据和方法。
首先,要明确三个概念:原型对象,函数对象,实例对象。
-
原型对象:每个实例对象都会有一个原型对象,这个原型对象上存放着这个类所共有的属性和方法。
-
原型对象还有一个重要的属性为construcor,用于指向构造函数,每次创建一个新实例对象时,就会调用这个构造函数,来为这个实例进行初始化,相当于对这个新的毛坯房进行一个装饰,添加一些基本的配置项。
-
所有对象的始祖是Object,万物之根,所有的对象都是由这个始祖开枝散叶而来。而Object是否有原型对象呢?如有。Object有原型对象,但这个原型对象指向null。(此处描述较为模糊,后面可能更正)。
-
-
函数对象(构造函数):函数对象相当于一个“装饰器”,用于初始化实例,为实例添加应有的属性和方法,容易理解,不多赘述。
-
所有的函数对象的 显式原型属性 (后面会解释,先码住)指向她的原型对象。
-
特别注意的是,函数对象(构造函数)是一个函数,那么她必定由Funtion创建,所以函数对象(构造函数)的 隐式原型属性(后面会解释,先码住)指向Function的原型对象上。
-
-
实例对象:每个由函数对象(构造函数)构建出来的实例身上,会有一个隐式原型属性指向函数对象的显式原型对象。
- 后面会举个例子来解释这个拗口原理,稍安勿躁。
大家需要记住,原型对象上有constructor属性,指向构造函数;函数对象(构造函数)会有一个显式原型属性指向原型对象;而实例身上会有一个隐式原型属性来指向函数对象(构造函数)的显式原型属性(回答了上文中的码住,大家可以理解为显式与隐式是函数对象和实例特有的属性)。
了解了这些基本原理(开胃小菜),那么开始我们的正题(大餐来了)。
-------------------------------------------------分割线--------------------------------------------------------
只放文字是枯燥的,下面结合图来分别解释一下 object/function/自定义实例对象这三个boss。
万物始祖,Object
图片是从大图中截取的,请忽略左下方多余的连线,会在文末附上整体图片。
Object原型对象
我们假设,Object对象的存储地址为001。作为万物始祖,Object原型对象的隐式原型对象指向null。之前我们说过,原型对象上必定有constructor属性,指向函数原型(构造函数)。
| 属性 | 值 |
|---|---|
| 地址 | 001 |
| __ proto __ | null |
| constructor | 002(Object函数对象) |
Object函数对象(构造函数)
紧接着,我们来介绍一下Object对应的函数原型(构造方法),我们假设这个对象的地址为002。之前我们说过,函数原型(构造函数)身上必定有prototype(显式原型属性)指向原型对象,地址001。特别注意的是,函数原型(构造函数)作为函数,肯定是由Function构建而来,所以她也是Function的实例,故存在隐式原型对象指向Function的原型对象。
捋一捋,作为函数原型,具有显式原型属性,指向原型对象。作为函数的实例,具有隐式原型属性,指向Function构造函数的显式原型对象,也就是Function原型对象(别急,等到后面讲Function就明白了)。
| 属性 | 值 |
|---|---|
| 地址 | 002 |
| prototype | 001(Object原型对象) |
| __ proto __ | 003(Function原型对象) |
世界BOSS,Function
所有的方法都是Function的猴子猴孙,所以称她为世界BOSS,看懂Function和Object,原型链理解起来不再话下。
Function原型对象
我们假设Function原型对象的存储地址为003。
- 特别注意的是,所有的原型都是Object原型的实例,所以Function原型对象也是Object原型对象的实例,存在一个隐式原型属性指向Object原型对象(实例的隐式原型属性指向构造函数的显式原型对象)。
- 每个原型对象都会有constructor属性指向构造方法。
| 属性 | 值 |
|---|---|
| 地址 | 003 |
| __ proto __ | 001(Object原型对象) |
| constructor | 004(Function构造函数) |
Function函数对象(构造函数)
- 作为函数对象(构造函数)必定有prototype属性指向Function原型对象。
- 特别注意的是,Function函数对象作为构造函数,其也是Function的实例,故存在隐式原型对象指向Function的原型对象。
| 属性 | 值 |
|---|---|
| 地址 | 004 |
| prototype | 003(Function原型对象) |
| __ proto __ | 003(Function原型对象) |
哈喽沃得,MyClass
当我们自定义一个类时,系统开辟一块空间放类的原型对象,我们假设地址为005.
MyClass原型对象
- 作为原型对象,是Object原型的实例,所以存在一个隐式原型属性指向Object原型对象(实例的隐式原型属性指向构造函数的显式原型对象)。
- 每个原型对象都会有constructor属性指向构造方法。
| 属性 | 值 |
|---|---|
| 地址 | 005 |
| __ proto __ | 001(Object原型对象) |
| constructor | 006(MyClass构造函数) |
MyClass函数对象(构造函数)
- 作为函数对象(构造函数)必定有prototype属性指向MyClass原型对象。
- 特别注意的是,MyClass函数对象作为构造函数,其也是Function的实例,故存在隐式原型对象指向Function的原型对象。
| 属性 | 值 |
|---|---|
| 地址 | 006 |
| prototype | 005(MyClass原型对象) |
| __ proto __ | 003(Function原型对象) |
MyClass实例对象
“我”终于出现了!作为一个实例,必定存在一个隐式原型属性指向MyClass原型对象(实例的隐式原型属性指向构造函数的显式原型对象)。
| 属性 | 值 |
|---|---|
| 地址 | 007 |
| __ proto __ | 005(MyClass原型对象) |
大功告成!
参考文献: