JS原型链

这篇文章是「深入ECMA-262-3」系列的一个概览和摘要。每个部分都包含了对应章节的链接,所以你可以阅读它们以便对其有更深的理解。

对象

ECMAScript做为一个高度抽象的面向对象语言,是通过对象来交互的。即使ECMAScript里边也有基本类型,但是,当需要的时候,它们也会被转换成对象。

一个对象就是一个属性集合,并拥有一个独立的prototype(原型)对象。这个prototype可以是一个对象或者null。*

让我们看一个关于对象的基本例子。一个对象的prototype是以内部的[[Prototype]]属性来引用的。但是,在示意图里边我们将会使用__<internal-property>__下划线标记来替代两个括号,对于prototype对象来说是:__proto__\。

对于以下代码:

basic-object.png

这些prototype有什么用?让我们以原型链(prototype chain)的概念来回答这个问题。

原型链

原型对象也是简单的对象并且可以拥有它们自己的原型。如果一个原型对象的原型是一个非null的引用,那么以此类推,这就叫作原型链。

原型链是一个用来实现继承和共享属性的有限对象链。

考虑这么一个情况,我们拥有两个对象,它们之间只有一小部分不同,其他部分都相同。显然,对于一个设计良好的系统,我们将会重用相似的功能/代码,而不是在每个单独的对象中重复它。在基于类的系统中,这个代码重用风格叫作类继承-你把相似的功能放入类A中,然后类B和类C继承类A,并且拥有它们自己的一些小的额外变动。

ECMAScript中没有类的概念。但是,代码重用的风格并没有太多不同(尽管从某些方面来说比基于类(class-based)的方式要更加灵活)并且通过原型链来实现。这种继承方式叫作委托继承(delegation based inheritance)(或者,更贴近ECMAScript一些,叫作原型继承(prototype based inheritance))。

跟例子中的类ABC相似,在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 };
// call the inherited method
b.calculate(30);  // 60
c.calculate(40);  // 80

规则很简单:如果一个属性或者一个方法在对象自身中无法找到(也就是对象自身没有一个那样的属性),然后它会尝试在原型链中寻找这个属性/方法。如果这个属性在原型中没有查找到,那么将会查找这个原型的原型,以此类推,遍历整个原型链(当然这在类继承中也是一样的,当解析一个继承的方法的时候-我们遍历class链( class chain))。第一个被查找到的同名属性/方法会被使用。因此,一个被查找到的属性叫作继承属性。如果在遍历了整个原型链之后还是没有查找到这个属性的话,返回undefined值。

注意,继承方法中所使用的this的值被设置为原始对象,而并不是在其中查找到这个方法的(原型)对象。也就是,在上面的例子中this.y取的是b和c中的值,而不是a中的值。但是,this.x是取的是a中的值,并且又一次通过原型链机制完成。

如果没有明确为一个对象指定原型,那么它将会使用__proto__的默认值-Object.prototype。Object.prototype对象自身也有一个__proto__属性,这是原型链的终点并且值为null。

下一张图展示了对象a,b,c之间的继承层级:

prototype-chain.png

注意: ES5标准化了一个实现原型继承的可选方法,即使用Object.create函数:

var b = Object.create(a, {y: {value: 20}}); var c = Object.create(a, {y: {value: 30}});

你可以在对应的章节获取到更多关于ES5新API的信息。 ES6标准化了 __proto__属性,并且可以在对象初始化的时候使用它。

通常情况下需要对象拥有相同或者相似的状态结构(也就是相同的属性集合),赋以不同的状态值。在这个情况下我们可能需要使用构造函数(constructorfunction),其以指定的模式来创造对象。

构造函数

除了以指定模式创建对象之外,构造函数也做了另一个有用的事情-它自动地为新创建的对象设置一个原型对象。这个原型对象存储在ConstructorFunction.prototype属性中。

换句话说,我们可以使用构造函数来重写上一个拥有对象b和对象c的例子。因此,对象a(一个原型对象)的角色由Foo.prototype来扮演:

// a constructor function
function Foo(y) {
this.y = y;
}
Foo.prototype.x = 10;
Foo.prototype.calculate = function (z) {return this.x + this.y + z;
};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
console.log(c.__proto__ === Foo.prototype)   // true//同时 Foo.prototype  同时会创建一个特殊的属性 constructor,
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

这个代码可以表示为如下关系:

这张图又一次说明了每个对象都有一个原型。构造函数Foo也有自己的__proto__,值为Function.prototypeFunction.prototype也通过其__proto__属性关联到Object.prototype。因此,重申一下,Foo.prototype就是Foo的一个明确的属性,指向对象b和对象c的原型。

正式来说,如果思考一下分类的概念(并且我们已经对Foo进行了分类),那么构造函数和原型对象合在一起可以叫作「类」。实际上,举个例子,Python的第一级(first-class)动态类(dynamic classes)显然是以同样的属性/方法处理方案来实现的。从这个角度来说,Python中的类就是ECMAScript使用的委托继承的一个语法糖。

注意: 在ES6中「类」的概念被标准化了,并且实际上以一种构建在构造函数上面的语法糖来实现,就像上面描述的一样。从这个角度来看原型链成为了类继承的一种具体实现方式:

// ES6

class Foo {constructor(name) {this._name = name;}getName {return this._name;}
}
class Bar extends Foo {getName {return super.getName + ' Doe';}
}
var bar = newBar('John');
console.log(bar.getName); // John Doe

转自JavaScript. The core.
http://www.yidianzixun.com/n/0CjThYEE?s=9&appid=xiaomi&ver=3.5.5&utk=03smxf0g

转载于:https://www.cnblogs.com/jiuyi/p/5331592.html

JS 原型链图形详解相关推荐

  1. JS原型与原型链终极详解

     一. 普通对象与函数对象   JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object ,Function 是JS自带的函数对象.下面举例说明 functi ...

  2. 最详尽的 JS 原型与原型链终极详解(1)(2)(3)===转载

    转载===方便以后复习 原文网址:https://www.jianshu.com/p/dee9f8b14771 一. 普通对象与函数对象 JavaScript 中,万物皆对象!但对象也是有区别的.分为 ...

  3. JS原型和原型链最详解(附图)

    目录 一.自定义构造函数 二.调用构造函数 三.构造函数.原型对象和实例之间的关系 四.isPrototypeOf() 五.Object.getPrototypeOf() 六.Object.setPr ...

  4. 详解JS原型链与继承

    详解JS原型链与继承 JavaScript 目录 摘自JavaScript高级程序设计: 概念 确定原型和实例的关系 原型链的问题 借用构造函数 组合继承 原型继承 寄生式继承 寄生组合式继承 new ...

  5. js打印三角形超详解

    js打印三角形超详解 j控制星星的总行数,i控制每行星星的打印个数 打印图形如下: (1) (2) //str=""用来存储星星// 理解步骤1:在一行输出6个星星如何操作,在循环 ...

  6. 走穿java23种设计模式-15责任链模式详解

    走穿java23种设计模式-15责任链模式详解 责任链模式是一种常见的行为模式. 一.责任链模式的现实场景 习伟过生日邀请了很多朋友到KTV一起庆祝,为了增加欢乐的气氛,习伟建议大家一起玩击鼓传花的游 ...

  7. Three.js - 摄像机的使用详解(透视投影摄像机、正交投影摄像机)

    一.两种摄像机的区别与比较 Three.js 库提供了两种不同的摄像机:透视投影摄像机和正交投影摄像机. 透视投影摄像机:这种摄像机的效果更贴近真实世界.也就是物体离摄像机越远,它们就会被渲染得越小. ...

  8. 简单粗暴地理解js原型链–js面向对象编程

    简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...

  9. 从实现角度分析js原型链

    从实现角度分析js原型链 欢迎来我的博客阅读:<从实现角度分析js原型链> 网上介绍原型链的优质文章已经有很多了,比如说: https://github.com/mqyqingfeng/B ...

最新文章

  1. 信息安全研究之数据安全专题
  2. 独家 | 使用机器学习预测房价(附链接)
  3. 【linux】spinlock 的实现
  4. flink on yarn模式下释放flink占用yarn的资源
  5. TTL电平、CMOS电平、RS232通信电平的概念及区别
  6. CSS之Box-sizing
  7. EMR on ACK 全新发布,助力企业高效构建大数据平台
  8. 使用live555制作rtsp客户端,捕获h264等解码
  9. angular1.x todolist 实现
  10. 论文赏析[TACL18]隐式句法树模型真的能学到句子中有意义的结构吗?
  11. 默纳克系统服务器怎么查故障,默纳克查历史故障
  12. 梦想cms-v1.4-后台存在任意文件读取漏洞
  13. 桌面PDF文件名太长无法删除的问题
  14. MySQL中concat()、concat_ws()、group_concat()三个函数的使用技巧案例与心得总结
  15. Java实现咖啡馆选餐系统
  16. 数据库公共字段自动填充
  17. 【数据架构系列-02】从《数据中台能力成熟度模型》的发布,聊聊火了的中台
  18. e580显卡驱动_搭载AMD RX 550独显!联想Thinkpad E580评测:能玩大型游戏的亲民商务本...
  19. hadoop常用命令及端口
  20. Chrome 浏览器的灵魂插件,盘他!

热门文章

  1. 加密解密技术—对称算法加密
  2. 免费迅雷会员VIP帐号获取器 – 迅雷离线下免费用
  3. neural network ppt for support vector machine
  4. 体育馆黑名单系统 的设定
  5. MacBook的mission control的功能
  6. 刘洪波雅思阅读9分班学习
  7. PPT科研绘图第二节 如何调整三维旋转参数
  8. 在图书馆学习红宝书的一天(二)· 慢慢看原型、原型链就看懂了~
  9. zookeeper命令行(zkCli.shzkServer.sh)使用及四字命令
  10. getOutputStream() has already been called for this response异常的原因和解决方法