js实现继承的方法以及优缺点( 二 )


对于原型链而言 , 借用构造函数有一个很大的优势 , 即可以在子类型构造函数中向超类型构造函数传递参数
function SuperType(name){ this.name = name;}function SubType(){//继承了SuperType , 同时还传递了参数 SuperType.call(this, "Nicholas"); //实例属性 this.age = 29;}var instance = new SubType();console.log(instance.name); //"Nicholas";console.log(instance.age); //29

借用构造函数问题: 方法都在构造函数中定义 , 因此函数复用就无从谈起了 。而且 , 在超类型的原型中定义的方法 , 对子类型而言也是不可见的 , 结果所有类型都只能使用构造函数模式
3. 组合继承组合继承(combination inheritance) , 有时候也叫做伪经典继承 , 指的是将原型链和借用构造函数的技术组合到一块 , 从而发挥二者之长的一种继承模式 。其背后的思路是使用原型链实现对原型属性和方法的继承 , 而通过借用构造函数来实现对实例属性的继承 。这样 , 既通过在原型上定义方法实现了函数复用 , 又能够保证每个实例都有它自己的属性
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"];}SuperType.prototype.sayName = function(){ console.log(this.name);};function SubType(name, age){//继承属性 SuperType.call(this, name);this.age = age;}//继承方法SubType.prototype = new SuperType();SubType.prototype.sayAge = function(){ console.log(this.age);};var instance1 = new SubType("Nicholas", 29);instance1.colors.push("black");console.log(instance1.colors); //"red,blue,green,black"instance1.sayName(); //"Nicholas";instance1.sayAge(); //29var instance2 = new SubType("Greg", 27);console.log(instance2.colors); //"red,blue,green"instance2.sayName(); //"Greg";instance2.sayAge(); //27组合继承避免了原型链和借用构造函数的缺陷 , 融合了它们的优点 , 成为JavaScript中最常用的继承模式 。而且 , instanceof和isPrototypeOf也能够用于识别基于组合继承创建的对象 。
无论什么情况下 , 都会调用两次超类型构造函数:一次是在创建子类型原型的时候 , 另一次是在子类型构造函数内部
4. 原型式继承这种方法并没有使用严格意义上的构造函数 。借助原型可以基于已有的对象创建新对象 , 同时还不必因此创建自定义类型
function object(o){ function F(){} F.prototype = o; return new F();}var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"]};var anotherPerson = object(person);anotherPerson.name = "Greg";anotherPerson.friends.push("Rob");var yetAnotherPerson = object(person);yetAnotherPerson.name = "Linda";yetAnotherPerson.friends.push("Barbie");console.log(person.friends); //"Shelby,Court,Van,Rob,Barbie"ECMAScript 5通过新增Object.create()方法规范化了原型式继承 。这个方法接收两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象 。在传入一个参数的情况下 , Object.create()与object()方法的行为相同 。
Object.create()方法的第二个参数与Object.defineProperties()方法的第二个参数格式相同:每个属性都是通过自己的描述符定义的 。以这种方式指定的任何属性都会覆盖原型对象上的同名属性
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"]};var anotherPerson = Object.create(person, { name: { value: "Greg" }});console.log(anotherPerson.name); //"Greg"
在没有必要兴师动众地创建构造函数 , 而只想让一个对象与另一个对象保持类似的情况下 , 原型式继承是完全可以胜任的 。不过别忘了 , 包含引用类型值的属性始终都会共享相应的值 , 就像使用原型模式一样
5. 寄生式继承创建一个仅用于封装继承过程的函数 , 该函数在内部以某种方式来增强对象 , 最后再像真的是它做了所有工作一样返回对象
function createAnother(original){ var clone = Object.create(original); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 console.log("hi"); }; return clone; //返回这个对象}在这个例子中 , createAnother()函数接收了一个参数 , 也就是将要作为新对象基础的对象 。然后 , 把这个对象(original)传递给object()函数 , 将返回的结果赋值给clone 。再为clone对象添加一个新方法sayHi() , 最后返回clone对象 。可以像下面这样来使用createAnother()函数:


推荐阅读