JavaScript 不包含传统的类继承模型,而是使用 prototype 原型模型。所以大家提到的JavaScript的继承其实就是基于原型的继承。
1.继承产生的原因—作用
C++有类的概念,比如说类`动物`,`猫`和`狗`都属于`动物`,有很多的相似性。如果单独构造这两者,效率不高,而如果定义一个基类,通过此基类及个性化设计来实现这两者将会比较高效。
所以继承的作用是让子类可访问父类的属性和方法.且子类也能做父类。
2.继承的简单实现
使用new关键字或者object.create。
两种大方法:
2.1.原型链继承(使用prototype)
我最开始理解的继承应该如下实现:
function ClassA(name){ this.name = name; } ClassA.prototype.sayName = function(){ alert(this.name); } var a1 = new ClassA('a1'); var a2 = new ClassA('a2'); a1.sayName();//a1 a2.sayName();//a2
以上实现确没有子类,扩展如下
function ClassA(){ } ClassA.prototype.name = 'A'; ClassA.prototype.sayName = function(){ alert(this.name); } var ClassB = new ClassA(); var b1 = new ClassB();// Uncaught TypeError: ClassB is not a constructor b1.sayName();
以上报错:Uncaught TypeError: ClassB is not a constructor
正确写法如下:
function ClassA(){ this.id =['A']; } ClassA.prototype.name = 'A'; ClassA.prototype.sayName = function(){ alert(this.name); } function ClassB(){ } ClassB.prototype = new ClassA(); ClassB.prototype.constructor = ClassB;// 不加这句,通过ClassB构造的实例的构造器反而是ClassA.加了这句避免混乱 var b1 = new ClassB(); var b2 = new ClassB(); b1.id.push ('b1'); console.log(b1.id,b2.id);//['A',b1'] ['A',b1']
缺点:
(1).来自原型对象的属性所有实例共享,所以有可能修改实例会修改原型
(2).不能向父类构造函数传参
继承:父类、子类、用子类构造的实例
2.2.类式继承
function ClassA(name){ this.name = name; this.id || (this.id = []); this.id.push(name); this.sayId = function(){ alert(this.id); }; } function ClassB(name){ ClassA.call(this,name); } var b1 = new ClassB('b1'); var b2 = new ClassB('b2'); console.log(b1.id);//["b1"] console.log(b2.id);//["b2"]
完全复制了父类的属性到子类上。
缺点:
(1).每个子类实例都持有新的sayId函数,占用内存,影响性能。
3.继承的实际使用
以上两种方法是原理方法,但是各有优缺点。基于这两种原理,又产生了一些有效的方法
3.1.组合继承(最常用)
function ClassA(name){ this.id = [name]; } ClassA.prototype.sayId = function(){ console.log(this.id); } function ClassB(name){ ClassA.call(this,name);//复制一份属性出来 } ClassB.prototype = new ClassA(); var b1 = new ClassB('B1'); var b2 = new ClassB('B2'); b1.id.push('b1'); b2.id.push('b2'); console.log(b1.id,b2.id);//["B1", "b1"] ["B2", "b2"]
缺点:
父类被调用了两次,浪费
3.2.寄生组合继承(最优)
function createChild(obj){
var Child = function(){};
Child.prototype = obj;
return new Child();
}
function ClassA(){
this.id = [1];
}
ClassA.prototype.sayId = function(){
console.log(this.id);
}
function ClassB(){
ClassA.call(this);
}
var ClassC = createChild(ClassA.prototype);
ClassC.constructor = ClassB;
ClassB.prototype = ClassC;
var b1 = new ClassB();
参考文章:
JavaScript中的继承方式