JavaScript中继承的那些事
引言
JS是一门面向对象的语言,但是在JS中没有引入类的概念,之前特别疑惑在JS中继承的机制到底是怎样的,一直学了JS的继承这块后才恍然大悟,遂记之。
假如现在有一个“人类”的构造函数:
借用构造函数
我们可以通过在子类型的内部调用超类型的构造函数来达到子类型继承超类型的效果。函数是在特定环境中执行的代码对象,因此可以通过call()或者apply()在新创建的对象上执行构造函数。
不过借用构造函数进行继承,难免会有方法都在构造函数中定义,无法实现函数的复用。并且在超类型的原型中定义的方法对于子类型是不可见的,结果所有类型都要使用构造函数进行继承,所以单独使用构造函数的情况比较少。
通过原型链
原型链的定义机制我在JavaScript中原型链的那些事中已经提过了,说到底,通过原型链实现继承根本是通过prototype属性进行实现的。
如果Man的原型指向的是Human的实例,那么Man原型对象中将会包括一个指向Human的指针,那么所有Man的实例就都可以继承Human了。
我们改变了Man的prototype的指向,让他等于一个Human的实例对象。即:
组合继承(伪经典继承)
组合继承的整体思想就是将原型链和借用构造函数同时使用,取两者的长处的一种继承模式。思路是使用原型链实现原型属性和方法的继承,借用构造函数来实现对实例属性的继承。这样做的好处是实现了函数的复用,同时又保证了每个属性都有自己的属性。
那么上面让“男人”继承“人类”就可以通过组合继承实现:
原型式继承
如果说继承的对象并不是构造函数呢?我们没有办法使用借用构造函数进行继承,这个时候我们就可以使用原型式继承。
这个继承模式是由道格拉斯·克罗克福德提出的。原型式继承并没有使用严格意义上的构造函数。而是借助原型可以在已有的对象上创建新的对象,同时还避免了创建自定义类型。所以道格拉斯·克罗克福德给出了一个函数:
我们可以创建一个新的临时性的对象来保存超类型上所有属性和方法,用来给子类型的继承。而这个就是这个函数要做的事。
在object函数内部先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的新实例。本质上其实就是object对传入的对象进行了一次浅复制。
现在有一个“男人”对象:
这里需要注意的是,这两个对象现在时普通的对象,而不是构造函数,所以我们无法使用上面的方法。
我们可以通过原型式继承,如下面的例子:
在ECMAScript中通过函数Object.create()规范了原型式继承,该方法接收两个参数,一个用于新对象原型的对象,第二个参数用于为新对象定义额外属性的对象,在传入一个参数的情况下,Object.create()和上面的object()函数作用相同。
拷贝继承
我们可以想一下其实继承的意思就是子类型把超类型的所有属性和方法拿过来放在自己身上。 那么我们可以将超类型的属性和方法全部拷贝给子类型,从而实现继承。
浅拷贝
我们可以实现一个方法,将超类型的对象传入方法,然后将对象的属性添加到子类型上并返回,具体代码如下:
具体使用可以这样:
使用方法类似于上面介绍的原型式继承。但是这样实现继承有一个很大的问题,那就是当对象的属性是引用类型值(数组,对象等)时,在拷贝过程中,子对象获得的只是一个内存地址,而不是真正的属性拷贝。
深拷贝
我们可以在浅拷贝的基础上进行深拷贝。我们知道,当在拷贝基本类型值时是在内存中新开辟了一块区域用于拷贝对象属性的存储,所以我们只需要递归下去调用浅拷贝就行了。
使用方法和浅拷贝类似,这里就不举例了。
寄生式继承
寄生式继承的思路就是创建一个用于封装继承过程的函数,在该函数内部以某种方式来增强对象,最后再向真的它做了所有工作一样返回对象。还是上面man和human两个对象间实现继承的例子:
在主要实现对象是自定义类型而不是构造函数的情况下,寄生式继承是一种有用的继承模式,其中使用的object函数不是必须的,任何能实现该功能的函数都可以。
寄生组合式继承
组合继承是JS中一种非常常用的继承模式,可是这个方式实现继承有一个问题,就是无论在任何情况下,都会调用两次超类型构造函数。一次是在创建子类型原型的时候,第二次是在子类型构造函数内部。子类型最终会包含超类型对象的全部实例属性,但是我们不得不在调用子类型构造函数时重写这些属性。如此在继承非常频繁的情况下就会造成内存过度损耗的情况了。这个时候,我们可以使用寄生组合式继承!
寄生组合式继承,就是借用构造函数来继承属性,通过原型链的混成形式来继承方法。具体思路是不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已,本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
基本模式如下:
让我们回到第一个问题:有一个“男人”的构造函数和“人类”的构造函数,我现在想让男人继承人类!
以上~