原型链(Prototype chain)

原型对象也是普通的对象,并且也有可能有自己的原型,如果一个原型对象的原型不为null的话,我们就称之为原型链(prototype chain)。

A prototype chain is a finite chain of objects which is used to implemented inheritance and shared properties.
原型链是一个由对象组成的有限对象链由于实现继承和共享属性。

想象一个这种情况,2个对象,大部分内容都一样,只有一小部分不一样,很明显,在一个好的设计模式中,我们会需要重用那部分相同的,而不是在每个对象中重复定义那些相同的方法或者属性。在基于类[class-based]的系统中,这些重用部分被称为类的继承 – 相同的部分放入class A,然后class B和class C从A继承,并且可以声明拥有各自的独特的东西。

ECMAScript没有类的概念。但是,重用[reuse]这个理念没什么不同(某些方面,甚至比class-更加灵活),可以由prototype chain原型链来实现。这种继承被称为delegation based inheritance-基于继承的委托,或者更通俗一些,叫做原型继承。

类似于类”A”,”B”,”C”,在ECMAScript中尼创建对象类”a”,”b”,”c”,相应地, 对象“a” 拥有对象“b”和”c”的共同部分。同时对象“b”和”c”只包含它们自己的附加属性或方法。

var a = {
x: 10,
calculate: function (z) {
return this.x + this.y + z
}
}; var b = {
y: 20,
__proto__: a
}; var c = {
y: 30,
__proto__: a
}; // 调用继承过来的方法
b.calculate(30); // 60
c.calculate(40); // 80

这样看上去是不是很简单啦。b和c可以使用a中定义的calculate方法,这就是有原型链来[prototype chain]实现的。

原理很简单:如果在对象b中找不到calculate方法(也就是对象b中没有这个calculate属性), 那么就会沿着原型链开始找。如果这个calculate方法在b的prototype中没有找到,那么就会沿着原型链找到a的prototype,一直遍历完整个原型链。记住,一旦找到,就返回第一个找到的属性或者方法。因此,第一个找到的属性成为继承属性。如果遍历完整个原型链,仍然没有找到,那么就会返回undefined。

注意一点,this这个值在一个继承机制中,仍然是指向它原本属于的对象,而不是从原型链上找到它时,它所属于的对象。例如,以上的例子,this.y是从b和c中获取的,而不是a。当然,你也发现了this.x是从a取的,因为是通过原型链机制找到的。

如果一个对象的prototype没有显示的声明过或定义过,那么__prototype__的默认值就是object.prototype, 而object.prototype也会有一个__prototype__, 这个就是原型链的终点了,被设置为null。

下面的图示就是表示了上述a,b,c的继承关系

图 2. 原型链

原型链通常将会在这样的情况下使用:对象拥有 相同或相似的状态结构(same or similar state structure) (即相同的属性集合)与 不同的状态值(different state values)。在这种情况下,我们可以使用 构造函数(Constructor) 在 特定模式(specified pattern) 下创建对象。

构造函数(Constructor)

除了创建对象,构造函数(constructor) 还做了另一件有用的事情—自动为创建的新对象设置了原型对象(prototype object) 。原型对象存放于 ConstructorFunction.prototype 属性中。

例如,我们重写之前例子,使用构造函数创建对象“b”和“c”,那么对象”a”则扮演了“Foo.prototype”这个角色:

// 构造函数
function Foo(y) {
// 构造函数将会以特定模式创建对象:被创建的对象都会有"y"属性
this.y = y;
} // "Foo.prototype"存放了新建对象的原型引用
// 所以我们可以将之用于定义继承和共享属性或方法
// 所以,和上例一样,我们有了如下代码: // 继承属性"x"
Foo.prototype.x = 10; // 继承方法"calculate"
Foo.prototype.calculate = function (z) {
return this.x + this.y + z;
}; // 使用foo模式创建 "b" and "c"
var b = new Foo(20);
var c = new Foo(30); // 调用继承的方法
b.calculate(30); // 60
c.calculate(40); // 80 // 让我们看看是否使用了预期的属性 console.log( b.__proto__ === Foo.prototype, // true
c.__proto__ === Foo.prototype, // true // "Foo.prototype"自动创建了一个特殊的属性"constructor"
// 指向a的构造函数本身
// 实例"b"和"c"可以通过授权找到它并用以检测自己的构造函数 b.constructor === Foo, // true
c.constructor === Foo, // true
Foo.prototype.constructor === Foo // true b.calculate === b.__proto__.calculate, // true
b.__proto__.calculate === Foo.prototype.calculate // true );

上述代码可表示为如下的关系:

图 3. 构造函数与对象之间的关系

上述图示可以看出,每一个object都有一个prototype. 构造函数Foo也拥有自己的__proto__, 也就是Function.prototype, 而Function.prototype的__proto__指向了Object.prototype. 重申一遍,Foo.prototype只是一个显式的属性,也就是b和c的__proto__属性。

最新文章

  1. javascript-模板方法模式-提示框归一化插件
  2. Visual Studio 2013 错误提示“未找到与约束匹配”的修正
  3. JavaWeb学习笔记——JavaBean的保存范围和删除
  4. GridView总结一:GridView自带分页及与DropDownList结合使用
  5. 转:Java NIO系列教程(四) Scatter/Gather
  6. PHP数字格式化,每三位逗号分隔数字,可以保留小数
  7. 部署WAR文件到tomcat
  8. tomcat 调优
  9. Springmvc异步上传文件
  10. HTTP 教程 转自 http://www.w3cschool.cc/http/http-tutorial.html
  11. ubuntu14.04 下安装mysql5.6
  12. [分享]Host文件的原理解释及应用说明
  13. Print Article hdu 3507 一道斜率优化DP 表示是基础题,但对我来说很难
  14. cxf webservice生成客户端代码及调用服务端遇到的问题
  15. (五)surging 微服务框架使用系列之缓存-reids
  16. 北大poj-1021
  17. Java修饰符final总结
  18. AssetBundle使用心得【资源加载】
  19. 使用R语言的RTCGA包获取TCGA数据--转载
  20. i++ 和 ++i的字节码指令

热门文章

  1. php实现备份数据库
  2. linux下搭建SVN
  3. linux学习笔记之 basename, dirname
  4. 总结Java虚拟机内存区域模型
  5. JSON数据写入和解析
  6. AR 前言
  7. Could not create SSL/TLS secure channel.
  8. python之字符编码
  9. C#动态系统托盘图标
  10. SQL Server常见的操作符