js实现继承的几种方式以及优缺点:JavaScript高级之继承的四种方式
js实现继承的几种方式以及优缺点:JavaScript高级之继承的四种方式解释下this[attr] = parentObject[i]中的this,谁调用了这个“方法名”,那么这个this就是谁。说明:图2:使用call或apply方式实现继承使用call或apply这种方式,本质上其实和第一种实现方式是一样的,都是利用了this。call和apply的使用方式请参考《JavaScript高级之call和apply的使用》。语法:
在上一篇文章《JavaScript高级之call和apply的使用》中,我们讲到了call和apply的作用就是:使用指定的对象调用当前函数,说白了,就是可以改变函数内部this的指向。对于call和apply的理解还是非常有必要的,因为call和apply同样也是实现JavaScript继承的方式之一。本文主要探讨下在JavaScript中如何去实现继承以及继承的实现方式。
一、对象冒充使用对象冒充的方式实现继承,就必须掌握this的用法,首先贴上代码如下:
图1:对象冒充的方式实现继承
既然要实现继承,那么就必须要有父类和子类,在这里我定义了Parent父类和Child子类。通过程序运行发现,child.sayName()居然打印出来了结果,可是child实例对象并没有sayName方法呀,而这个sayName方法是定义在了父类Parent上,这样就相当于子类Child把父类Parent中的方法给继承了下来。为什么会这样?
图2:使用call或apply方式实现继承
使用call或apply这种方式,本质上其实和第一种实现方式是一样的,都是利用了this。call和apply的使用方式请参考《JavaScript高级之call和apply的使用》。
三、扩展Object类语法:
说明:
解释下this[attr] = parentObject[i]中的this,谁调用了这个“方法名”,那么这个this就是谁。
思路:
其实通过扩展Object类的方式去实现继承很好理解,为Object类的原型对象添加一个方法,这个方法需要接受一个父类型的实例对象,而我这个方法内部循环的去遍历这个父类型的实例对象,把父类型实例对象中的所有的属性添加到this所指向的对象中,那么就说明了this指向的这个对象也拥有了父类中所有的属性。
代码如下:
图3:扩展Object类实现继承
在这里再多啰嗦几句:
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();
代码如下:
图4:使用原型方式实现继承
这里再啰嗦一句:之所以child可以去调用sayName方法,主要原因是我们已经将Parent的实例对象赋值给了Child的原型对象,而当我们去调用一个实例对象上不存在的属性或方法时(比如child实例对象根本没有sayName方法),该实例对象就会自动去找该构造函数的原型对象,发现Child的原型对象上是存在sayName方法的,所以是可以调用的。
总结:到目前为止,JavaScript的高级知识就告一段落了,可以发现的是,其实每个知识点都是有联系的,我们由最开始讲到的原型,到原型继承,到原型链,到call和apply的使用,再到今天讲的继承,发现实际上是有一个层次递进关系的,我们学习应该是要把每个点给彻底吃透,这样才会走的更远。