原型链继承
function Car(){ this.wheel = "wheel"; this.arr = [1,2]; this.drive = function (speed){
} } function Bmw(){}; Bmw.prototype = new Car(); //核心 var bmw = new Bmw(); var bmw1 = new Bmw(); console.log(bmw.wheel) //wheel bmw1.arr.push(3); console.log(bmw.arr) //[1,2,3] console.log(bmw1.arr); //[1,2,3]
核心:把父类的实例化对象赋值给子类原型。
缺点:1、值类型成员不影响,引用类型成员是所有实例对象所共享的,容易被改变。(引用类型成员包括数组、对象、函数);
2、在创建子类型的实例时,不能向超类型的构造函数中传递参数。(实际上是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数)
构造函数继承
function Car(direction){ this.wheel = "wheel"; this.arr = [1,2]; this.direction = direction; this.drive = function (){ console.log("方向:"+this.direction); console.log("车速:"+this.speed); } } function Bmw(speed){ this.speed = speed; Car.call(this,"正北"); //核心 }; var bmw = new Bmw(1); var bmw1 = new Bmw(2); console.log(bmw.wheel) //wheel bmw1.arr.push(3); console.log(bmw.arr) //[1,2] console.log(bmw1.arr); //[1,2,3] bmw.drive(); //车速:1 bmw1.drive(); //车速:2
核心:在子类中调用call,相当于把父类的实例属性复制一遍给子类。
解决了原型链的共享和不能传参的缺点。
缺点:由于call相当于把父类函数复制给子类了,所以两个子类并未引用同一个函数,而是每个子类都有一个drive函数。内存浪费,影响性能。
组合继承(常用)
function Car(){ this.wheel = "wheel"; this.arr = [1,2]; } Car.prototype.drive = function(){ //核心 console.log("车速:"+this.speed); } function Bmw(speed){ this.speed = speed; Car.call(this); //核心 }; Bmw.prototype = new Car(); //核心 var bmw = new Bmw(1); var bmw1 = new Bmw(2); console.log(bmw.wheel) //wheel bmw1.arr.push(3); console.log(bmw.arr) //[1,2] console.log(bmw1.arr); //[1,2,3] bmw.drive(); ////车速:1 bmw1.drive(); //车速:2
核心:组合继承就是把构造函数继承和原型链继承组合到一起。
构造函数继承的缺点就是函数,把函数放到父函数的原型链上就可以了。
缺点:父函数的构造函数被调用了2次。子类和子类的原型链上有相同的属性。如下图:
arr和wheel属性重复,有些内存浪费。
寄生组合继承(最佳)
function excess(obj){ //核心 var F = function(){}; F.prototype = obj; return new F(); } function Car(){ this.wheel = "wheel"; this.arr = [1,2]; } Car.prototype.drive = function(){ //核心 console.log("车速:"+this.speed); } function Bmw(speed){ this.speed = speed; Car.call(this); //核心 }; Bmw.prototype = excess(Car.prototype); //核心 Bmw.constructor = Bmw; //核心 var bmw = new Bmw(1); var bmw1 = new Bmw(2); console.log(bmw.wheel) //wheel bmw1.arr.push(3); console.log(bmw.arr) //[1,2] console.log(bmw1.arr); //[1,2,3] bmw.drive(); ////车速:1 bmw1.drive(); //车速:2
核心:将父类的原型传入函数excess来获得一个新的原型(剪掉了多余的属性),将新的原型附给子类的原型。
没有什么缺点了。