JavaScript之原型链(一)
2016-07-28 22:48
381 查看
就JavaScript的语言和对象系统的实现来讲,对象(Object Instance)并没有原型,而构造器(Constructor)有原型。对象只有“构造自某个原型”的问题,并不存在“持有(或拥有)某个原型”的问题。“原型也是对象实例”是一个最关键的性质,这是它与“类继承体系”在本质上的不同。——《JavaScript语言精粹与编程实践》
翻了好几本书,其中就有周爱民老师的《JavaScript语言精粹与编程实践》。看过一些章节之后感叹真是难得的佳作,可惜最近事情不少,还没能静下心来细细体会全部吃透,但总算有所心得,不管对错先记下来日后有机会再修改。
原型链的最上层是一个空的Object对象实例,通过构造器生成的对象实例obj1和obj2其实分别就是一个指向构造出他们的原型的引用。图中原型和obj2又分别有各自的属性。对象属性的查找就是遍历该对象的原型链,直到原型为空或找到改属性。
预定义对象中有两个比较重要:Object对象和Function对象。JavaScript的普通对象(new Object()创建的实例)是Object对象的实例,JavaScript的函数是Function对象的对象实例。如果用原型继承的相关术语来解释,即JavaScript中的普通对象的原型对象是Object.prototype,JavaScript中的函数的原型对象是Function.prototype。当然,Function.prototype与一个普通对象并没有本质区别。还有,当一个函数的prototype有意义之后,这个函数就摇身一变成了一个“构造器”。
OK,接下来通过分析一段简单的代码来搞清楚原型链到底是什么东东。
该代码运行后,JavaScript的内部环境应该如下图所示:
上图中需要说明的是,每个构造器都会有一个prototype属性指向构造器的原型,每个对象实例都会有一个constructor属性指向它的构造器,以此形成原型链的链状结构。接下来用在上一篇博客中搭好的编译环境验证一下上图的准确性:
接下来在上一小节的代码之后增加一行:
代码运行后JavaScript的内部环境如下图所示:
接下来是验证:
可以看到运行本小节追加的赋值语句之后,Language.prototype多了一个a属性。
代码运行后JavaScript的内部环境如下图所示:
接下来是验证:
上图中通过方法hasOwnProperty()可以知道某属性是否是对象自身的属性。可以看出a不是lan1自身的属性,因为它是lan1的原型的属性。但是在遍历lan1属性的for循环中,a也出现在了遍历结果之中,这正是“如果在对象中没有指定属性,则尝试遍历对象的整个原型链,直到原型为空或找到该属性”规则的体现。
翻了好几本书,其中就有周爱民老师的《JavaScript语言精粹与编程实践》。看过一些章节之后感叹真是难得的佳作,可惜最近事情不少,还没能静下心来细细体会全部吃透,但总算有所心得,不管对错先记下来日后有机会再修改。
一、原型复制与原型链
先来个看图说话(说话内容摘自上述《JavaScript语言精粹与编程实践》):原型链的最上层是一个空的Object对象实例,通过构造器生成的对象实例obj1和obj2其实分别就是一个指向构造出他们的原型的引用。图中原型和obj2又分别有各自的属性。对象属性的查找就是遍历该对象的原型链,直到原型为空或找到改属性。
二、原型链
JavaScript被作为一种扩展语言而设计,需要在内建对象的宿主环境中运行。JavaScript从宿主环境获取的对象树就被称为宿主对象,宿主对象的根节点就是全局对象。通过使用全局对象,可以访问所有其他预定义的对象、函数和属性。全局对象不是任何对象的属性,所以它没有名称。全局对象只是一个对象而不是类,既没有构造函数,也无法实例化一个新的全局对象。预定义对象中有两个比较重要:Object对象和Function对象。JavaScript的普通对象(new Object()创建的实例)是Object对象的实例,JavaScript的函数是Function对象的对象实例。如果用原型继承的相关术语来解释,即JavaScript中的普通对象的原型对象是Object.prototype,JavaScript中的函数的原型对象是Function.prototype。当然,Function.prototype与一个普通对象并没有本质区别。还有,当一个函数的prototype有意义之后,这个函数就摇身一变成了一个“构造器”。
OK,接下来通过分析一段简单的代码来搞清楚原型链到底是什么东东。
1、全局对象与函数
首先是如下一段函数声明与赋值:var Language = function (name) { this.name = name; };
该代码运行后,JavaScript的内部环境应该如下图所示:
上图中需要说明的是,每个构造器都会有一个prototype属性指向构造器的原型,每个对象实例都会有一个constructor属性指向它的构造器,以此形成原型链的链状结构。接下来用在上一篇博客中搭好的编译环境验证一下上图的准确性:
2、对象的属性
上一小节中的Language是在全局上下文中定义的变量,所以,由之前的图中可以看出,Language成为了全局对象的一个属性。其实Language也有prototype,因为Language可以成为其他对象的构造器。Language的prototype是Object对象实例。接下来在上一小节的代码之后增加一行:
var Language = function (name) { this.name = name; };
Language.prototype.a ='aaa';
代码运行后JavaScript的内部环境如下图所示:
接下来是验证:
可以看到运行本小节追加的赋值语句之后,Language.prototype多了一个a属性。
3、对象的属性与原型链
继续追加代码:var Language = function (name) { this.name = name; };
Language.prototype.a ='aaa';
var lan1 = new Language('JavaScript');
代码运行后JavaScript的内部环境如下图所示:
接下来是验证:
上图中通过方法hasOwnProperty()可以知道某属性是否是对象自身的属性。可以看出a不是lan1自身的属性,因为它是lan1的原型的属性。但是在遍历lan1属性的for循环中,a也出现在了遍历结果之中,这正是“如果在对象中没有指定属性,则尝试遍历对象的整个原型链,直到原型为空或找到该属性”规则的体现。
三、未待续完
关于JavaScript的原型链,写到这里并未结束。下回再继续研究下所谓的“内部原型链”。相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- JavaScript演示排序算法
- javascript实现10进制转为N进制数
- 最后一次说说闭包
- Ajax
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 对一个分号引发的错误研究
- 设计模式---状态模式在web前端中的应用
- 异步流程控制:7 行代码学会 co 模块
- ES6 走马观花(ECMAScript2015 新特性)
- JavaScript拆分字符串时产生空字符的原因
- Canvas 在高清屏下绘制图片变模糊的解决方法
- Redux系列02:一个炒鸡简单的react+redux例子