JavaScript高级之prototype原型链

一、前言

本文主要聊聊JavaScript中的原型链。现在再来回顾总结一下上一篇《JavaScript高级之prototype原型继承》的一个结论,我们由最开始抛出的一个问题:“JS中,为什么说所有类的父类都是Object?”引出了一个结论就是:原型对象也是一个对象,是Object类下的一个实例,进而又引申出,只要是通过构造函数的方式去创建实例对象,这些实例对象都是可以去调用Object类中的属性和方法,进而得出结论:JS中所有类的父类都是Object。好了,解释到这里,现在再来去深入了解一下什么是原型链。

二、问题:Object构造函数有与之对应的Object原型对象吗?

哇哦,这个问题读起来是不是有点拗口嘞,其实也还好了吧。什么意思呢?先说答案,这个是必须的,Object构造函数也一定有与之对应的Object原型对象。下面直接看代码,如下:

<script type="text/javascript"/>

function Person(username){

this.username = username;

}

var p1 = new Person('zhangsan');

</script>

我们说,当JS引擎去加载一个构造函数的时候,就会自动地为该构造函数去创建相对应的原型对象,那么如上例代码所示,就是说当JS引擎去加载Person构造函数的时候,就会自动地为Person构造函数去创建Person原型对象,那么相对应的,当JS引擎去加载Object构造函数的时候,也应当自动地为Object构造函数去创建Object原型对象;当JS引擎去加载Date构造函数的时候,理所应当的会自动地为Date构造函数去创建Date原型对象等等。这个唯一的区别就是:这个Person构造函数是我们自己定义的,而Object构造函数是JS本身就定义好的而已(tips:你JS系统当然不能偏心了,不管是自定义还是本身提供,你都应当对每一个构造函数都自动创建对应的原型对象啦)。如下图所示:

JavaScript高级之prototype原型链

图1:原型链部分图示

三、由上图1引发的问题思考

进行问题思考之前,首先对图1做个说明:我们在var p1 = new Person('zhangsan')进行实例化后,实际上在p1实例对象内部会有一个“prototype”的属性,就指向了创建p1对象的Person构造函数所对应的Person原型对象,而作为Person原型对象,本身也是一个对象,是由Object构造函数去实例化的,那么这个Person原型对象里面是不是也应该有一个“prototype”的属性呢?答案是肯定的,因为对于p1实例对象来说,它内部有一个prototype属性,而Person原型对象也是作为一个实例对象,那么它的内部也应当有一个prototype属性。我们的p1对象中的prototype属性指向了Person构造函数的原型对象,那么问题是:Person原型对象中的prototype属性又是指向了哪里呢?

答案:由上图所得到,Person构造函数的原型对象中的prototype属性应该是指向了创建Person原型对象的构造函数的原型对象,那么我们知道Person原型对象是由Object构造函数所创建的,那么应当的Person原型对象中的prototype属性应该是指向了Object构造函数的原型对象。如图所示:

JavaScript高级之prototype原型链

图2:原型链部分图

四、Person原型对象中的prototype属性执行Object构造器的原型的有什么作用?

作用:如果我们向Object构造器的原型对象里面添加属性或者方法的话,就意味着我们的JS系统里面的所有的对象都可以拥有这个属性或者方法,这个是非常有用的。比如说我们要调用p1.xxx()方法,那么如果p1对象里面没有这个xxx()方法,那么p1对象就会去找Person构造器的Person原型对象中是否有这个xxx()方法,发现Person构造器的原型对象里面也没有xxx()方法,那么这个时候Person原型对象中的prototype属性也会自动去找Object原型中的xxx()方法。到此为止,这样做的用处在哪里呢?大家可以想一想:如果我现在有一个方法叫做run()方法,我需要这个run()方法可以被JS系统中所有的对象都可以使用,那么如何做?我们可以这样想,既然JS中所有类的父类都是Object,那么我能不能把这个run方法添加到Object类里面呢,答案是不行的,因为我们不可能去修改JS系统里面已经提供好的Object类,但是我们可以把我们的run()方法添加到Object构造函数所对应的Object原型对象里面去,这样就可以实现了,因为假设说当我们的p1实例对象要去调用run()方法时,p1实例对象内部没有此方法,那么p1实例对象就会去找Person原型对象是否有run()方法,发现如果没有,那么Person原型对象也会继续去向Object原型对象里面去找是否有run()方法,发现是有的,那么p1实例对象就可以使用了run()方法了,等等,以此类推。总结就是:使用这种方式,我们就可以非常方便的去扩展Object的功能,也就是所有类的功能扩展。

这种一级一级地具有层级关系的查找,就非常的类似于链一样,所以也叫做原型链。

五、图2引发的深层次问题:Object原型对象内部是否也应该有prototype属性?

仔细分析发现,其实图2也仍然是不完整的,为什么?我们说原型对象也是一个对象,那么这个Object原型对象也应该是有创建这个Object原型对象的构造函数所创建的,那么这个构造函数又是谁呢?哇哦,写到这里,是不是你又若有所思起来了呢?我们说JS中所有的类的父类都是Object,Object已经作为了最顶级的类存在了,那么这个Object类的上级又是谁呢?如果有上级的话,是不是这个上级也应该有一个构造函数对创建呢?......哇哦,是不是有“世界上的第一个人是谁的问题”的感慨哦!哈哈,其实到目前为止,理论上来说,Object原型对象中确实也是应该有一个prototype属性去指向某个构造函数这么一个东东,实际上,在这里我们可以简单的理解为:Object原型对象中的prototype指向的是计算机系统的一块区域了,是一个未知的区域,什么都不是,可以理解为“null”。如图:

JavaScript高级之prototype原型链

图3:原型链完整图


猜你喜欢

转载自blog.csdn.net/smile_lg/article/details/79650150