原创 《js高级程序设计》三——4原型式继承 5寄生式继承 6寄生组合式继承 小结

原型式继承

没有使用严格意义上的 构造函数。借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型

function object(o){
 	function F(){}
 	F.prototype = o;
 	return new F();
} 

在 object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的 原型,后返回了这个临时类型的一个新实例。从本质上讲,object()对传入其中的对象执行了一次浅复制

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");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie" 

新对象将 person 作为原型,所以它的原型中就包含一个基本类型值属性 和一个引用类型值属性。这意味着 person.friends 不仅属于 person 所有,而且也会被 anotherPerson 以及 yetAnotherPerson 共享。实际上,这就相当于又创建了 person 对象的两个副本。

ECMAScript 5通过新增 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");

var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie" 

Object.create()方法的第二个参数与Object.defineProperties()方法的第二个参数格式相 同:每个属性都是通过自己的描述符定义的。以这种方式指定的任何属性都会覆盖原型对象上的同名属 性

var person = {
 	name: "Nicholas",
 	friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person, {
 	name: {
 		value: "Greg"
 	}
});

alert(anotherPerson.name); //"Greg" 

支持 Object.create()方法的浏览器有 IE9+、Firefox 4+、Safari 5+、Opera 12+和 Chrome。
在没有必要兴师动众地创建构造函数,而只想让一个对象与另一个对象保持类似的情况下,原型式 继承是完全可以胜任的。不过别忘了,包含引用类型值的属性始终都会共享相应的值,就像使用原型模 式一样。

寄生式继承

parasitic
寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该 函数在内部以某种方式来增强对象,后再像真地是它做了所有工作一样返回对象

function createAnother(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" 

在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。前面示 范继承模式时使用的 object()函数不是必需的;任何能够返回新对象的函数都适用于此模式。

使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率;这一 点与构造函数模式类似

寄生组合式继承

组合继承大的 问题就是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是 在子类型构造函数内部。没错,子类型终会包含超类型对象的全部实例属性,但我们不得不在调用子 类型构造函数时重写这些属性

组合继承:

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); //第二次调用 SuperType()
 	this.age = age;
}
SubType.prototype = new SuperType(); //第一次调用 SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
 	alert(this.age);
}; 

在这里插入图片描述
有两组 name 和 colors 属性:一组在实例上,一组在 SubType 原型中。这就是调 用两次 SuperType 构造函数的结果

所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法
其背 后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型 原型的一个副本而已。
本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型 的原型。

寄生组合式继承的基本模式如下所示:

function inheritPrototype(subType, superType){
 	var prototype = object(superType.prototype); //创建对象
 	prototype.constructor = subType; //增强对象
 	subType.prototype = prototype; //指定对象
} 
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);
}; 

只调用了一次 SuperType 构造函数,并且因此避免了在 SubType. prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf()。开发人员普遍认为寄生组合式继承是引用类型理想的继承范式

YUI的 YAHOO.lang.extend()方法采用了寄生组合继承,从而让这种模式首次 出现在了一个应用非常广泛的 JavaScript库中。要了解有关 YUI的更多信息,请访问 http://developer. yahoo.com/yui/。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值