JavaScript实现继承的六种方式实例讲解
JavaScript实现继承的六种方式实例讲解
1.借用构造函数
借用构造函数实现继承,就是在子类型构造函数内部调用父类型构造函数,使用apply()和call()方法将父类型的构造函数绑定在子类型上。
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ SuperType.call(this); //继承了 SuperType } var instance1 = new SubType(); instance1.colors.push("black"); //instance1实例得到了一个color属性的副本,改变的是instance1这个实例的color属性,而不是其原型对象中的color属性。 alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green"
通过使用apply()或call()方法,实际上是在新创建的SubType实例的环境下调用SuperType构造函数。SubType的每个实例都会具有自己的color属性的副本。
2.原型链继承
依靠原型链来实现继承,就是利用原型让一个引用类型继承另一个引用类型的属性和方法。
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; } function SubType(){ this.subproperty = false; } SubType.prototype = new SuperType(); //创建 SuperType 的实例,并将该实例赋给SubType.prototype,这样SubType就继承了SuperType。 SubType.prototype.getSubValue = function(){ return this.subproperty; } var instance = new SubType(); //存在于SuperType 的实例中的所有属性和方法,也存在于 SubType.prototype 中了。 alert(instance.getSuperValue()); //true
3.组合继承
组合继承就是将原型链和借用构造函数的技术组合到一起。
使用原型链实现对原型属性和方法的继承;通过借用构造函数来实现对实例属性的继承。这样在原型上定义的方法实现了函数的复用,又能保证每个实例都有自己的属性。
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); //继承属性 this.age = age; } SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; //添加constructor属性是为了弥补重写原型而失去的默认constructor属性。 SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27 //instance1和instance2这两个实例分别拥有自己的属性,又拥有相同的方法。
4.原型式继承
借助原型可以基于已有的对象创建新对象,而不必因此创建自定义的类型。
function object(o){ function F(){} ; F.prototype = o; return new F(); } //在 object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例。 var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; //person对象作为后续对象的继承,后续的对象在person的基础上根据具体的需求进行修改。 var anotherPerson = object(person); //创建的新对象将person作为原型。原型中包含一个基本类型值的属性和一个引用类型值的属性,那么这个引用类型值的属性friends,将会共享给新创建的对象。 anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
ES5提供了Object.create()方法来实现原型式继承。
两个参数:用作新对象原型的对象、为新对象定义其他属性的对象(可选)。
只传入一个参数时,Object.create()方法和object()方法行为相同:
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = Object.create(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); console.log(person);
Object.create()方法的第二个参数与Object.defineProperties()方法的第二个参数格式相同:每个属性都通过自己的描述符定义。重新定义的属性会覆盖原型对象上的同名属性。
var anotherPerson = Object.create(person, { name: { value: "Greg" } }); alert(anotherPerson.name); //"Greg"
5.寄生式继承
寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。
function createAnother(original){ //参数original是作为新对象基础的对象 var clone = object(original); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 alert("hi"); }; return clone; //返回这个对象 } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi" //基于person返回了一个新对象。新对象不仅拥有person的所有属性和方法,同时也拥有自己的sayHi()方法。
6.寄生组合式继承
寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上就是使用寄生式继承来继承超类型的原型,再将结果指定给子类型的原型。
function inheritPrototype(subType, superType){ var prototype = Object(superType.prototype); //创建对象 prototype.constructor = subType; //增强对象 subType.prototype = prototype; //指定对象 }
函数接受两个参数:子类型和超类型。
第一步:创建超类型原型的一个副本。
第二步:为创建的副本添加属性,这里添加的constructor 属性是为了弥补因重写原型而失去的默认的 constructor 属性。
第三步:将新创建的对象赋值给子类型的原型。
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function(){ alert(this.age); };