什么是继承? 子类继承父类中的一些属性和方法
原型继承
让子类的原型指向父类的实例 Children.prototype = new Parent(); [细节] 1、我们首先让子类的原型指向父类的实例,然后再向子类原型上扩展方法,防止提前增加方法,等原型重新指向后, 之前在子类原型上扩展的方法都没用了(子类原型已经指向新的空间地址了) 2、让子类原型重新指向父类实例,子类原型上原有的constructor就没有了,为了保证构造函数的完整性, 我们最好给子类的原型重新手动设置constructor属性值:Children.prototype.constructor = Children; [ 原理 ] 原型继承,并不是把父类的属性和方法COPY一份给子类,而是让子类的原型和父类原型之间搭建一个链接的桥梁, 以后子类(或者子类的实例),可以通过原型链的查找机制,找到父类原型上的方法,从而调取这些方法使用即可 [ 特征 ] 子类不仅可以继承父类原型上的公有属性和方法,而且父类提供给实例的那些私有的属性方法, 也被子类继承了(存放在子类原型上,作为子类公有的属性和方法)
function Parent() { this.x = 100; } Parent.prototype.getX = function () { console.log(this.x); }; function Children() { this.y = 200; } Children.prototype = new Parent();//=>最好在扩展子类原型方法之前完成 Children.prototype.constructor = Children; Children.prototype.getY = function () { console.log(this.y); }; var child = new Children();
call继承
在子类的构造体中,把父类做普通方法执行,让父类方法中的THIS指向子类的实例 [ 原理 ] 把父类构造体中私有的属性和方法,原封不动复制了一份给子类的实例(继承完成后,子类和父类是没关系的) [ 细节 ] 我们一般把call继承放在子类构造体中的第一行,也就是创建子类实例的时候,进来的第一件事情就是先继承, 然后再给实例赋值自己私有的(好处:自己的可以把继承过来的结果替换掉)
function Parent() { this.x = 100; } Parent.prototype.getX = function () { console.log(this.x); }; function Children() { //=>this:child 子类的实例 Parent.call(this);//=>让Parent执行,方法中的THIS依然是子类的实例(在父类构造体中写的 THIS.XXX=XXX 都相当于在给子类的实例增加一些私有的属性和方法) this.y = 200; } var child = new Children();
寄生组合继承
Object.create([obj]):创建一个空对象(实例),把[obj]作为新创建对象的原型
var obj={name:'我的兜兜有糖'}; var newObj=Object.create(obj); newObj.__proto__===obj
寄生组合式继承完成了一个需求:
子类公有的继承父类公有的(原型继承的变通)
子类私有的继承父类私有的(call继承完成)
function Parent() { this.x = 100; } Parent.prototype.getX = function () { console.log(this.x); }; function Children() { Parent.call(this); this.y = 200; } Children.prototype = Object.create(Parent.prototype); Children.prototype.constructor = Children; Children.prototype.getY = function () { console.log(this.y); };
思考题:
自己实现一个类似于Object.create的方法
Object.myCreate = function myCreate(obj) { var Fn = new Function(); Fn.prototype = obj; return new Fn(); };