欢迎大家来到IT世界,在知识的湖畔探索吧!
在上一篇文章《JavaScript高级之call和apply的使用》中,我们讲到了call和apply的作用就是:使用指定的对象调用当前函数,说白了,就是可以改变函数内部this的指向。对于call和apply的理解还是非常有必要的,因为call和apply同样也是实现JavaScript继承的方式之一。本文主要探讨下在JavaScript中如何去实现继承以及继承的实现方式。
一、对象冒充
使用对象冒充的方式实现继承,就必须掌握this的用法,首先贴上代码如下:
既然要实现继承,那么就必须要有父类和子类,在这里我定义了Parent父类和Child子类。通过程序运行发现,child.sayName()居然打印出来了结果,可是child实例对象并没有sayName方法呀,而这个sayName方法是定义在了父类Parent上,这样就相当于子类Child把父类Parent中的方法给继承了下来。为什么会这样?
解释:原因在于子类Child的定义上,可以看到,在Child函数内部,为Child定义了一个method属性,而这个method属性又指向了Parent函数(也就是说method属性实际上是一个方法),然后又去调用了这个method方法(实际是调用了Parent函数),好了,原因就出在了这里,当我通过this.method(name)执行的时候,这个this本身指的是Child的实例对象,但是实际上是调用的Parent函数,那么对于Parent函数来说,Parent函数内部的this又该是谁呢?难道是Parent的实例对象吗?答案显然不是的,因为我们说函数内部的this具体是指向谁,是由这个函数到底是由哪个对象来去调用,那么现在显然是通过Child的实例对象来去调用的,所以实际上Parent函数中的this实际上是this.method(name)这句代码中的this,而这个代码中的this确确实实是Child的实例对象。通过调用this.method(name)就相当于为Child实例对象也添加了一个sayName方法,那么理所应当的Child实例对象当然可以调用sayName方法了。在这里还要强调一句,delete this.method这句代码也是必不可少的,因为当我们使用sayName完毕之后,这个method属性其实就没有存在的必要了。
二、使用call,apply方法
代码如下:
使用call或apply这种方式,本质上其实和第一种实现方式是一样的,都是利用了this。call和apply的使用方式请参考《JavaScript高级之call和apply的使用》。
三、扩展Object类
语法:
说明:
解释下this[attr] = parentObject[i]中的this,谁调用了这个“方法名”,那么这个this就是谁。
思路:
其实通过扩展Object类的方式去实现继承很好理解,为Object类的原型对象添加一个方法,这个方法需要接受一个父类型的实例对象,而我这个方法内部循环的去遍历这个父类型的实例对象,把父类型实例对象中的所有的属性添加到this所指向的对象中,那么就说明了this指向的这个对象也拥有了父类中所有的属性。
代码如下:
在这里再多啰嗦几句:
1、为什么是扩展Object类,通过对Object的原型对象添加属性的方式呢?这个是因为原型链的性质决定的,因为当我们对Object的原型对象添加属性或方法时,我们所创建的任何的实例对象都可以拥有此属性和方法。所以这里child实例对象是可以调用show方法的。
2、这种方式实际上就是循环遍历父类型的实例对象中的所有的属性和方法然后添加到子类的实例对象中,那么实例对象也就拥有了父对象中所有的属性和方法,就相当于是继承了下来。
四、使用原型方式
语法:
子类.prototype = new 父类();
例如:Child.prototype = new Parent();
思路:
再来回顾一下之前的一个问题:为什么说Object是所有类的父类?是因为在JS系统中,所有类在被加载完毕之后,会自动的去创建类的原型对象,那么这个原型对象又是怎么创建的呢?我们知道这个原型对象是Object类的实例对象,也就是“类名.prototype = new Object()”,那么也就是说Object类下面的所有的属性和方法都会被这个原型对象所拥有。比如说,Person.prototype = new Object(),由于Object类下面的所有的属性和方法都会被Person原型对象所拥有,也就是被Person类所拥有,那么就可以说,Object是被Person所继承了,那么现在问题来了:我任意的给你两个类A和B,我要实现A继承B,该如何做呢?其实就是:
A.prototype = new B();
代码如下:
这里再啰嗦一句:之所以child可以去调用sayName方法,主要原因是我们已经将Parent的实例对象赋值给了Child的原型对象,而当我们去调用一个实例对象上不存在的属性或方法时(比如child实例对象根本没有sayName方法),该实例对象就会自动去找该构造函数的原型对象,发现Child的原型对象上是存在sayName方法的,所以是可以调用的。
总结:到目前为止,JavaScript的高级知识就告一段落了,可以发现的是,其实每个知识点都是有联系的,我们由最开始讲到的原型,到原型继承,到原型链,到call和apply的使用,再到今天讲的继承,发现实际上是有一个层次递进关系的,我们学习应该是要把每个点给彻底吃透,这样才会走的更远。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/34305.html