前端面试题系列—— JavaScript模拟类式继承
类式继承的需求
SuperClass是父类,SubClass是子类。我们需要达到的效果是,子类继承父类公有的属性和方法,方法依然为子类公有,子类继承父类的实例属性和方法,属性为子类各个实例自己的。举个栗子:
function SuperClass( name ) { this.name = name; } SuperClass.prototype.sayName = function () { alert ( this.name ); } function SubClass() {} inheritClass( SubClass, SuperClass );// inheritClass 是将要实现的类式继承操作 var sub1 = new SubClass( 'jack' ); var sub2 = new SubClass( 'king' ); alert( sub1.name == 'jack' );// 期待返回true alert( sub2.name == 'king' );//期待返回true sub1.sayName(); //期待 alert( 'jack' )
inheritClass( SubClass, SuperClass )该如何实现呢,首先继承原型链:
function SuperClass( name ) { this.name = name; } SuperClass.prototype.sayName = function () { return this.name; } function SubClass() {} SubClass.prototype = new SuperClass();// 形成原型链 var sub1 = new SubClass( 'jack' ); var sub2 = new SubClass( 'king' ); alert( sub1.name == 'jack' );// 期待返回flase; alert( sub1.name ); //'jack' alert( sub2.name == 'king' );//期待返回true; sub1.sayName(); //alert(' jack' );
可见name并不是每个实例自己的,实际上是子类公有的,在SubClass.prototyp.name上得到的,那如何改进呢,继续往下看:
function SuperClass( name ) { this.name = name; } SuperClass.prototype.sayName = function () { return this.name; } function SubClass() { SuperClass.apply( this, arguments ); } SubClass.prototype = new SuperClass();// 形成原型链 var sub1 = new SubClass( 'jack' ); var sub2 = new SubClass( 'king' ); alert( sub1.name == 'jack' );// true; alert( sub2.name == 'king' );//true; sub1.sayName(); //alert(' jack' );
我们利用apply来实现了该功能,但是SuperClass.prototyp.name依然存在,如果属性比较多的话是很大的浪费。如何继续改进呢,问题出在SubClass.prototype = new SuperClass();这个语句上,我们需要这里仅仅执行公有的方法和属性继承的操作。我们可以借用构造函数来完成这个任务:
function SuperClass( name ) { this.name = name; } SuperClass.prototype.sayName = function () { return this.name; } function SubClass() { SuperClass.apply(this, arguments); } function prototypeInherit( o ) { function F(){}; F.prototype = o; return new F(); } function inheritClass( SubClass, SuperClass ) { var prototype = prototypeInherit( SuperClass.prototype ); prototype.constructor = SubClass; SubClass.prototype = prototype; } inheritClass( SubClass, SuperClass );// inheritClass 是将要实现的类式继承操作 var sub1 = new SubClass( 'jack' ); var sub2 = new SubClass( 'king' ); alert( sub1.name == 'jack' );//true alert( sub2.name == 'king' );//true alert( sub1.sayName() );//'jack' alert( sub1.constructor.name );
分析下两个函数:inheritClass的核心是构造一个SubClass.prototype:prototypeInherit( o )利用了一个公的构造函数F使得实例的属性和方法不会传到子类的prototype上。inheritClass( SubClass, SuperClass )需要做的是将prototype的constructor修正为SubClass,之前为SuperClass。小作业:想想之前为什么是SuperClass?