解析“用ES5原型链实现的组合继承”
2021-01-13 本文已影响0人
老陈要上天
用ES5实现继承,就是用原型链实现。只要把子类和父类的原型链打通就解决了主要问题。最常用的是组合继承:
1、先看第1个关键语句
Father.call(this, age)
。这句话的作用很明显,是在Child()执行时,当执行到Father()就把this强行绑定到Child函数的上下文。我们知道函数内用声明在this下的属性/方法,是属于实例的,和this相关的就只和实例相关。在这里实例化new Child(30,”上海浦东”) 的时候,this.age=age执行时this指向Child的实例,所以最终Child的实例既拥有age属性又拥有address,也就是说子类的实例得到(继承)了父类的属性。Father.call(this, age)解决了属性/方法定义在实例上的情形,那么下两句关键语句解决的就是属性/方法定义在函数原型上的情形。
2、看第2个关键语句
Child.prototype=new Father()
。这句话首先创建了一个父类实例,此时这个Father父类的实例是{age:undefined}
对象;然后让Child.prototype指向这个对象,Child.prototype是干嘛的,默认情况下Child.prototype可是Child所有实例的原型,把它指向Father的实例意义就是让Child的所有实例的原型指向Father的某一个实例(或者说让Father的一个实例成为Child所有实例的原型)。那么Child子类的实例就可以顺着原型链访问到属于Father原型上的属性/方法了。原型链如下图:
3、第3个关键句Child.prototype.constructor=Child
是个细节。默认情况下Child.prototype.constructor就是等于Child的(Child.prototype是{constructor:f}
这么一个对象),而第2个关键语句Child.prototype=new Father()执行完,Child.prototype就被改变了,此时上面instance的constructor就会是Father,子类实例的构造器怎么能是父类呢,显然不对。所以需要显式的给constructor重新赋值Child。题外话,为什么instance.constructor会是Father呢?constructor默认是构造函数独有的属性,也就是普通对象是没有的,instance是
{age:30,address:”上海浦东”}
对象,不是函数,所以没有constructor,就要去它原型上找,原型是new Father()出来的对象,也不是函数,就要再去上一级原型上找,也就是去Father.prototype上找,而Father.prototype.constructor就是Father。