所谓继承,就是子类继承父类中的属性和方法。
方案一:原型继承
方法:子类的原型指向父类的一个实例。
function A() { this.x = 100; } A.prototype.getX = function getX() { console.log(this.x); }; function B() { this.y = 200; } B.prototype.sum=function(){} B.prototype = new A; //B子类 => A父类,让子类B的原型指向父类A的实例
B.prototype.getY = function getY() { console.log(this.y); }; let b = new B;
通过B.prototype = new A这一句话达成继承。
js中的面向对象的机制都是基于原型链完成的,所以js中的继承也可以是基于原型链的,但这其中又有很多弊端。
比如B之前的原型B.prototype上的方法b已经查找不到,b的constructor应该是B,但现在是A,b可以通过b.__proto__或b.__proto__.__proto__肆意修改父类上的属性和方法,而父类上不管私有还是公有的属性和方法都会成为子类公有的,这些种种问题都是需要注意的,这大概就是IE浏览器禁止使用__proto__的原因吧。
方案二:call继承
方法:把父类当做普通函数执行,让其执行的时候,方法中的this变为子类的实例即可。
function A() { this.x = 100; } A.prototype.getX = function getX() { console.log(this.x); }; function B() { //call继承 A.call(this); //=>this.x = 100; => b.x=100; this.y = 200; } B.prototype.getY = function getY() { console.log(this.y); }; let b = new B;
call继承只能继承父类中的私有属性(继承的私有属性赋值给子类实例的私有属性),而且是类似拷贝过来一份,不是链式查找;因为只是把父类当做普通的方法执行,所以父类原型上的公有属性方法无法被继承过来。
方案三:寄生组合继承
方法:call继承+变异版的原型继承共同完成的。
function A() { this.x = 100; } A.prototype.getX = function getX() { console.log(this.x); }; function B() { A.call(this); this.y = 200; } //=>Object.create(OBJ) 创建一个空对象,让其__proto__指向OBJ(把OBJ作为空对象的原型) B.prototype = Object.create(A.prototype); B.prototype.constructor = B; //把constructor补上 B.prototype.getY = function getY() { console.log(this.y); }; let b = new B; console.log(b);
这个方案利用了call继承实现私有到私有,利用原型继承实现了公有到公有,当然还是原型继承的一些弊端应该注意。
方案四:ES6中class类
class A { constructor() { this.x = 100; } getX() { console.log(this.x); } } //=>extends继承和寄生组合继承基本类似 class B extends A { constructor() { super(); //=>一但使用extends实现继承,只要自己写了constructor,就必须写super this.y = 200; } getY() { console.log(this.y); } } let b = new B;
其实extends继承和寄生组合继承基本类似,而且必须加上super()函数,它相当于A.call(this)。
项目中我们会用到继承地方比如自己写插件或者类库的时候,还有就是react中用class实现继承。