原型模式

每个函数都有一个 prototype 属性,它指向一个对象,该对象的用途是包含可以由特定类型的所有实例共享的属性和方法。按照字面意思来理解,那个 prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象可以让所有对象实例共享它所包含的属性和方法,而不必在构造函数中定义对象实例的信息,如下面的例子所示。

function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){ return this.name };

var person1 = new Person();
alert( person1.sayName() ); // Nicholas
var person2 = new Person();
alert( person2.sayName() ); // Nicholas

默认情况下,所有的原型对象都会自动获得一个 constructor 属性(当然还有从 Object 继承而来的),它包含一个指向 prototype 属性所在函数的指针,而通过这个构造函数还可继续为原型对象添加其他属性和方法。当调用构造函数创建一个新实例后,该实例会有一个内部指针(在此以 [[Prototype]] 来表示)指向构造函数的原型对象。比如下图就展示了上面的例子中各个对象之间的关系。
[img]http://dl2.iteye.com/upload/attachment/0128/3517/84d6b60f-148c-3276-bc17-dc8d846b57da.png[/img]
虽然无法访问到 [[Prototype]],但可以通过原型对象的 isPrototypeOf(obj) 来确定对象之间是否存在这种关系。还可以通过 Object.getPrototypeOf(obj) 返回原型对象的值。
对象实例可以访问保存在原型对象中的值,但不能通过对象实例重写其中的值,而是会屏蔽掉原型对象中的同名属性,这种修改不会影响其他对象实例,而且可以使用 delete 操作符删除对象实例重新定义的属性,从而恢复被屏蔽的属性。
正如上面所述:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。所以当让原型对象等于另一个类型的实例时,此时的原型对象将包含一个指向另一个原型的指针,那个原型相应地也包含这一个指向另一个构造函数的指针。如此层层递进,就构成了实例与原型的链条,即所谓的原型链。
实现原型链有一种基本模式,其代码大致如下。

function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){ return this.property; };

function SubType(){
this.subproperty = false;
}
SubType.prototype = new SuperType(); // 继承了 SuperType
SubType.prototype.getSubValue = function(){ return this.subproperty; };

var instance = new SubType();
alert(instance.getSuperValue()); // true

这里没有使用 SubType 默认提供的原型,而是给它换了一个新原型,就是 SuperType 的实例。所以新原型不仅具有 SuperType 的实例所拥有的全部属性和方法,而且其内部还有一个指向 SuperType 原型的指针。最终结果就是:instance 指向 SubType 的原型,SubType 的原型由指向 SuperType 的原型。getSuperValue() 方法仍然还在 SuperType.prototype 中,当 property 则位于 SubType.prototype 中,因为它是 SuperType 的一个实例属性。不过这里要注意的是,instance.constructor 现在指向的是 SuperType,因为 SubType 的 constructor 实际上是继承自 SuperType 的原型。
事实上,上面所说的原型链还少一环。因为所有引用类型默认都继承了 Object,而这个继承也是通过原型链实现的,因此默认原型都会包含一个指向 Object.prototype 的内部指针,这也正是所有自定义类型都会继承 toString()、valueOf() 等方法的根本原因。结合上面所述,上面这个例子的完整原型链就可以下图来表示。
[img]http://dl2.iteye.com/upload/attachment/0128/4442/8d20f8fb-cb03-393a-bc89-6f30929f39e5.png[/img]

注:摘自《JavaScript 高级程序设计》第 6 章 -- 面向对象的程序设计。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值