分享人:韩鹏
目录
1.背景介绍
2.知识剖析
3.常见问题
4.解决方案
5.编码实战
6.扩展思考
7.参考文献
8.更多讨论
JavaScript语言的对象体系,不是基于“类”,而是基于构造函数(constructor)和原型(prototype)。
原型对象:只要创建一个新函数,就会根据特定的规则为该函数创建一个prototype属性指向其原型对象,默认情况下原型对象会自动获得一个constructor属性,该属性包含一个指向prototype属性所在函数的指针。
Function.prototype.constructor === Function //true
构造函数:本身是一个函数,出于创建特定类型新对象的目的而定义的,内部使用this变量,需要和new配合使用来创建实例,this变量会绑定在实例对象上。
原型链的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的指针。如果:我们让原型对象A等于另一个类型B的实例,那么原型对象A就会有一个指针指向B的原型对象,相应的B的原型对象中保存着指向其构造函数的指针。假如B的原型对象又是另一个类型的实例,那么上述的关系依旧成立,如此层层递进,就构成了实例与原型的链条。
注意: 通过原型链实现继承时,不能使用对象字面量创建原型方法,因为这样做会重写原型链。
问题: 原型链很强大,可以利用它来实现继承,但是也有一些问题,主要的问题还是包含引用类型值的原型属性会被所有实例共享。因此我们在构造函数中定义实例属性。但是在通过原型来实现继承时,原型对象其实变成了另一个类型的实例。于是原先定义在构造函数中的实例属性变成了原型属性了。
原型链的另一个问题: 在创建子类型的实例时,不能在不影响所有对象实例的情况下,给超类型的构造函数传递参数。
为了解决原型中包含引用类型值带来的一些问题,引入了借用构造函数的技术。这种技术的基础思想是:在子类型构造函数的内部调用超类型构造函数。
借用构造函数的方式可以在子类型的构造函数中向超类型构造函数传递参数。
构造函数模式的问题: 在于方法都在构造函数中定义,函数复用无从谈起,因此,借用构造函数的模式也很少单独使用。
组合继承指的是将原型链和借用构造函数的技术组合在一块,从而发挥二者之长。即:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
组合继承避免了原型链和构造函数的缺陷,融合了他们的有点,成为JavaScript中最常用的继承模式。而且,instanceOf和isPropertyOf()也能够识别基于组合继承创建的对象。
这是另一种继承,没有严格意义上的构造函数。思路是:借助原型可以基于已有的对象创建新对象,同时还不必要创建自定义类型。
在object()函数内部,先创建一个临时的构造函数,然后将传入的对象作为构造函数的原型,最后返回这个临时类型的一个新实例。从本质上讲,object()对传入其中的对象执行了一次浅复制。
寄生式继承是与原型式继承紧密相关的一种思路,与寄生式构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。
使用寄生式继承来为对象添加函数,会由于不能做到函数的复用而降低效率;这一点和构造函数继承模式类似。
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链来继承方法。寄生组合式继承的基本思路:不必为了指定子类型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承超类型的原型,然后再将结果指定给子类型的原型。
组合继承最大的问题就是无论什么情况下,都会调用两次超类型构造函数Parent():一次是在创建子类型原型的时候( Parent.call(this,name); ),另一个是在子类型构造函数内部( Child.prototype = new Parent(); )。
寄生组合式继承的基本思路:不必为了指定子类型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。
参考一:JavaScript高级程序设计(第3版)
参考二:JS继承的6种方式(CSDN)
参考二:JS继承的常用方法
感谢大家观看
BY : 韩鹏