js继承的方式及其优缺点

js继承方法

前因:ECMAScript不支持接口继承,只支持实现继承
一、原型链
概念:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而 实例都包含一个指向原型对象的内部指针,让这个原型对象(子的原型)等于要继承的引用类型(父)的实例,由于引用类型(父)的实例包含一个指向(父)原型对象的内部指针,以此类推,层层递进,便构成实例与原型的链条,即原型链。
基本思想:利用原型让(子)引用类型继承(父)引用类型的属性和方法
基本模式的代码(参考红宝书):
默认原型:所有函数的默认原型都是Object实例,所以都会继承toString()和valueOf()等默认方法
确定原型和实例的关系方法:
(1)通过使用instanceof()
如:alert(instance instanceOf Object); //true
(2)通过使用isPrototypeOf()
如:alert(Object.prototype.isPrototyOf(instance)); //true
注意点:
(1)给原型添加方法一定要放在替换原型的语句之后
(2)在通过原型链实现继承时,不能使用对象字面量创建原型方法
原型链存在的问题:
(1)子类型的所有实例都可以共享父类型的属性
(2)子类型的实例无法在不影响所有对象的情况下,给父类型的构造函数传递参数
二、借用构造函数继承(伪造对象或经典继承)
基本思想:在子类型构造函数的内部调用超类型构造函数(通过使用apply()和call()方法也可以在(将来)新创建的对象上执行构造函数);
代码(参考红宝书):
存在问题:方法都在构造函数中定义,函数复用变得没有意义
补充:通过call()或者appla()调用父类型时,可以进行传参
三、组合继承(伪经典继承,原型链和借用构造函数技术组合)
基本思想:使用 原型链实现对原型属性和方法的继承(主要想 继承方法),而通过 借用构造函数来实现对 实例属性的继承(子类型的实例内部存在同名属性,从而对父类型的同名属性进行屏蔽);最后同时避免了原型链会被继承时会共享同一个父类型属性和借用构造函数的函数复用的缺陷
代码(参考红宝书):
/*组合继承*/
// 父类型
function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
}

//设置父类型的sayName方法
SuperType.prototype.sayName = function () {
alert(this.name);
}

// 子类型
function SubType(name,age) {
// 借用构造函数的方法继承"属性",该代码会在新建的实例里面添加和父类型相同的属性
SuperType.call(this,name);
this.age = age;
}

// 通过原型链继承方法
SubType.prototype = new SuperType();
SubType.prototype.costructor = SubType; //原型对象指向构造函数的指针(constructor)
SubType.prototype.sayAge = function () {
alert(this.age);
}

// 实例
var instance1 = new SubType("Jack",29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Jack"
instance1.sayAge(); //29

var instance2 = new SubType("Greg",27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg"
instance2.sayAge(); //27
/*组合继承*/
缺点:两次调用父类构造函数:(第一次是在创建子类原型的时候,第二次是在子类构造函数内部) ;从而造成子类继承父类的属性,一组在子类实例上,一组在子类原型上(即在子类原型上创建不必要的多余的属性) 
四、原型式继承
基本思想:借助原型可以基于已有的的对象创建新对象,即如在一个函数Object内部,先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型(实际上执行了浅复制),最后返回这个临时类型的新实例。
代码(参考红宝书):
补充:ES5新增的Object.create()方法拥有和object()方法同样的效果,但是Object.create()方法接受两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性(会覆盖作新对象原型的对象上的同名属性)的对象
举例子如下:

五、寄生式继承
基本思想:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象
代码(参考红宝书):
缺点:不能做到函数复用导致降低效率
六、寄生组合式继承
概念:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
基本思想:没有必要为了指定子类型的原型而调用超类型的构造函数(函数复用),我们需要的是超类型原型的副本。本质:使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
代码(参考红宝书):

猜你喜欢

转载自blog.csdn.net/dengdongxia/article/details/79596644