JavaScript高级之prototype原型继承

一、前言

本文主要聊聊JavaScript中的原型继承。现在来回想一下上一篇我的文章《JavaScript高级之prototype原型》中对原型的理解,我说,原型就是对象类型原型的引用,当我们通过构造函数去创建一个实例对象的时候,如果程序要访问实例对象中不存在的属性时,这个实例对象就会自动去该构造函数所对应的原型对象里面去找。好啦,现在我们来重点看下什么是原型的继承。

二、问题:所有类的父类都是Object类,为什么?

tips:再来重复一下,JavaScript中是没有“”的概念,只有“对象”的概念。这里的叫法仅仅是为了方便,在我的上一篇《JavaScript高级之prototype原型》一文中有详细的解释。

好啦,再回答这个问题之前,我们再来去思考一个问题,原型对象是什么?刚刚才解释了原型,怎么现在又拿来说了,哈哈,这里我要说的侧重点不同,刚才说原型就是对象类型原型的引用,那其实说白了,原型也是一个对象,那么既然是一个对象,那么这个对象肯定也必须是由一个构造函数去实例化的,那么问题是:这个原型对象又是哪个构造函数的实例对象呢?说的是不是有点晕嘞,好吧,我举个例子:

<script type="text/javascript">

function Person(username){

this.username = username;

}

var p1 = new Person('zhangsan');

</script>

先来看下这个代码:var p1 = new Person("zhangsan");我们说通过Person构造函数的方式去new了一个Person对象,或者说是通过Person构造函数的方式去实例化了一个对象,而p1变量是实例化对象的引用。注意:这里为了表达方便,就说p1是一个对象,那么既然p1是一个对象,那么p1是Person构造函数的一个对象,因为p1对象的创建是由Person构造函数去产生的。好,如果明白了这一点,那么现在再来去思考刚才的问题:原型对象也是一个对象,那么这个原型对象又是通过哪个构造函数去产生的呢?

Person.prototype指的就是原型对象,那么这个Person.prototype的原型对象是通过哪个构造函数生成的呢?答案是:原型是一个对象,是Object类下的一个实例,换句话说,这个原型对象是通过Object函数去产生的。哇塞,原来是这样子啊,那么用代码表示就是:Person.prototype = new Object()。

三、Person.prototype = new Object(),该如何去理解?

解释:当JS引擎去加载Person构造函数的时候,就会自动地为Person构造函数去创建Person的原型对象,当系统去创建Person原型对象的时候,JS引擎默认会执行这么一条语句,即:Person.prototype = new Object()也就是说这个原型对象是Object类的一个实例,那么既然原型对象是Object类的一个实例对象,那么理所应当的是这个原型对象就会拥有Object类中所有的属性和方法,那么当我们通过Person构造函数去实例化对象的时候,那么这些实例对象就可以通过原型对象去使用这些属性和方法,所以说Object类是所有类的父类。话不多说,直接代码举例并上图,如下:

<script type="text/javascript">

function Person(username){

this.username = username;

}

var p1 = new Person('zhangsan');

p1.toString();

</script>

JavaScript高级之prototype原型继承(JS中一个类的父类是Object?)

图1:prototype原型继承

如图所示:tips:图中的解释就是我现在解释的内容。我单独拿出来再解释一下。

首先看程序,我的问题是:为什么我们可以p1.toString()呢?咦,是哦,还真从来没有考虑过这个问题,那么我们想一下到底是为什么可以呢?p1对象里面明明压根就没有toString()方法呀,之所以可以调用,原因都在上图中了。解释:刚才也提到了,原型对象也是一个对象,是Object类的实例对象,那么JS引擎在去创建Person原型对象的时候,肯定也是要通过一个类去创建的,那么这个类就是Object,在创建原型对象的时候,JS引擎会执行类似于这种代码:Person.prototype = new Object(),只要是“new”,那么就意味着“实例化”,那么实例化就又意味着Object类中的属性和方法都会被Person的原型对象所拥有,比如说Object类中就有toString()方法,那么也就意味着Person的原型对象里面也有toString()方法,那么当p1对象去调用toString()的时候,由于p1对象压根就没有toString()方法,那么按照之前所说,当一个实例对象去访问一个不存在的属性或方法时,就会自动去找构造函数所对应的原型对象,现在一看,哇哦,原来Person原型对象里面已经有toString()方法,那么p1对象也就自然的拥有toString()方法,当然可以调用toString()方法了。那么把这种思想再扩展一下,就是:只要是通过构造函数的方式去创建任何的实例对象,那么这些实例对象都是可以去调用Object类中的属性和方法,这个就类似继承关系,准确来说就是原型继承,这个也就是为什么说JS中所有类的父类都是Object类的原因了。

猜你喜欢

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