Web程序员应该知道的Javascript prototype原理
有同事问了我几个和Javascript的类继承的小问题,我在也不太理解的情况下,胡诌了一通. 回来以后有些内疚, 反省一下, 整理整理Javascript的prototype的原理, 自己清楚点, 也希望对别人也有帮助.
首先js里面没有类这回子事情, 虽然class是js的保留字, 但是到现在也没派上任何用场. 在js里面, 几乎所有的东西都是对象, 函数也是对象, 所以函数可以赋值给别的变量. 另外js对象也可以用数组的方式访问, 也就是说访问obj1.something, 也可以写成obj1['something'].
在js里虽然没有类, 但是有一个在类编程里常用的的概念, Constructor构造器, 或者叫构造函数. 语法上Constructor跟普通的js函数没有区别, 但是Constructor前面加上new关键字就可以产生新的对象.
那么”new Constructor()”这样调用时到底做了什么事情呢?
1. js运行环境首先创建一个空对象
2. 把this变量指向这个对象
3. 把__proto__指向这个构造器的prototype属性
4. 通过this把属性和方法加在这个对象上
5. 最后会把this指向的对象return出来(当然你也可以显示的return别的对象,这是情况跟我讨论的有点不一样)
这里有2个概念比较重要, 第一是Constructor的prototype属性, 它是Constructor的一个保持共享属性和方法的对象. 二通过该Constructor生成的对象的__proto__属性, 它指向了那个prototype对象. 对象的Constructor可以通过该对象的constructor属性获得.
我们定义一个简单的Constructor Demo(), 然后通过他生成一个aDemo对象, 在Chrome的console里把aDemo打出来看到的结果是这样的,这是我们能很清楚的看出这种关系.
01
02
03
04
05
06
|
function DemoA(){ this .title = "this is a demo constructor" ; this .f1 = function (){} } var aDemo = new DemoA(); console.log(aDemo); |
换一种写法,
01
02
03
04
05
06
|
function DemoB(){ this .title = "this is a demo constructor" ; } DemoB.prototype.f2 = function () {}; var bDemo = new DemoB(); console.log(bDemo); |
其实跟前面没多大区别, 不过这一次f2()不在创建出来的对象上, 而是在对象的__proto__指向的构造器DemoB上. 这样的好处是当使用DemoB创建很多对象时, 比较节省内存.
js的prototype搜索链 prototype Chain
js的运行环境是这样使用构造器的prototype的. 当我们对第一个对象调用其方法时, js运行环境首先看, 这个对象本身有没有这个方法, 如果有就直接调用. 如果没找到, 就查找这个对象的__proto__属性指向的对象(就是前面说的该对象的构造器的prototype属性), 如果有该方法就调用, 没有继续查找__proto__属性指向对象的__proto__属性指向的对象, 以此类推. 直到最后, 找到js所有的对象都会指向默认指向的Object(算是js的根对象吧). 所以如果我们给Object上增加个方法, 所以的js对象都能使用.
由于js有对对象函数的prototype chain搜索的特性, 我们可以利用这点来模拟类似其他语言里类(class)的效果. 如:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
function DemoA(){ this .title = "this is a demo constructor" ; this .f1 = function (){} } function DemoB(){ this .title = "this is b demo constructor" ; this .f2 = function (){} } DemoB.prototype = new DemoA(); var bDemo = new DemoB(); console.log(bDemo); |
这时我们通过bDemo对象, 不但能调用bDemo上的DemoB的f2()方法, 也能__proto__同对对prototype的搜索, 在bDemo上直接调用DemoA的f1()方法.
由于这种写法在语法上太啰嗦, 不容易理解, 我可以定义一个这样的函数.
01
02
03
|
function inherit(Child, Parent) { Child.prototype = new Parent(); } |
这样我们前面的例子可以写成这样, 效果是一样的:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
function DemoA(){ this .title = "this is a demo constructor" ; this .f1 = function (){} } function DemoB(){ this .title = "this is b demo constructor" ; this .f2 = function (){} } inherit(DemoB, DemoA); var bDemo = new DemoB(); console.log(bDemo); |
Web程序员应该知道的Javascript prototype原理的更多相关文章
- [转]Web程序员必须知道的 Console 对象里的九个方法
一.显示信息的命令 01 1: <!DOCTYPE html> 02 2: <html> 03 3: <head> 04 4: <title&g ...
- Android 程序员必须知道的 53 个知识点
1. android 单实例运行方法 我们都知道 Android 平台没有任务管理器,而内部 App 维护者一个 Activity history stack 来实现窗口显示和销毁,对于常规从快捷方式 ...
- PHP程序员应该知道的15个库
最几年,PHP已经成为最受欢迎的一种有效服务器端编程语言.据2013年发布的一份调查报告显示,PHP语言已经被安装在全球超过2.4亿个网站以及210万台Web服务器之上.PHP代表超文本预处理器,它主 ...
- 嵌入式程序员应知道的0x10个基本问题
来源:网络 嵌入式程序员应知道的0x10个基本问题 1 . 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)#define SECONDS_PER_YEAR (60 ...
- 嵌入式程序员应知道的0x10个C语言Tips
[1].[代码] [C/C++]代码 跳至 [1] ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ...
- (转)程序员应该知道的10个eclipse调试技巧
调试不仅可以查找到应用程序缺陷所在,还可以解决缺陷.对于Java程序员来说,他们不仅要学会如何在Eclipse里面开发像样的程序,更需要学会如何调试程序.本文介绍了Java程序员必知的10个调试技巧, ...
- Java程序员应该知道的20个有用的lib开源库
一般一个经验丰富的开发者,一般都喜欢使用开源的第三方api库来进行开发,毕竟这样能够提高开发效率,并且能够简单快速的集成到项目中去,而不用花更多的时间去在重复造一些无用的轮子,多了解一些第三方库可以提 ...
- Git / 程序员需要知道的12个Git高级命令
众所周知,Git目前已经是分布式版本控制领域的翘楚,围绕着Git形成了完整的生态圈.学习Git,首先当然是学习Git的基本工作流.相比于SVN等传统版本控制系统来说,Git是专为分布式版本控制而生的强 ...
- 成为嵌入式程序员应知道的0x10个基本问题
预处理器(Preprocessor)1 . 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define SECONDS_PER_YEAR (60 * 60 * 2 ...
随机推荐
- MFC绘图小实验(2)
1,以正五边形的5个顶点为基础,隔点存储构成五角星.填充模式采用WINDING.五角星边界线为5个像素宽的蓝色实线,内部使用红色填充. CRect rect; //定义矩形 GetClientRect ...
- TCP/IP,http,socket,长连接,短连接——小结(转)
概要: 之前对这几个概念有点糊涂,查阅了些资料,稍微概括下他们的区别吧.如有错误,请拍~~~ 先看图: TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层. 在 ...
- 嵌入式开发之hi3519--- pcie dma和dma cache 缓存更新sync memery
http://blog.csdn.net/likeping/article/details/42235111 linux下dma 管理 http://blog.csdn.net/skyflying20 ...
- (转)Android 5.1.1 源码目录结构
转自:http://blog.csdn.net/tfslovexizi/article/details/51888458最近公司培训新同事,我负责整理一点关于android的基础知识,遥想当年,刚接触 ...
- Python 3.x标准模块库目录
出处:http://blog.csdn.net/sadfishsc/article/details/10390065 文本 1. string:通用字符串操作 2. re:正则表达式操作 3. dif ...
- js 去掉重复数组
js去掉重复数组 重点一:字符串转数组 strArr.join(',') 重点二:做循环数组删除的时候,每次循环就把color[i] 去对比i之前所有数组color组合起来的字符串 比如 : i=1 ...
- ABBYY FineReader操作技巧
使用ABBYY FineReader OCR文字识别软件工作即快速又简单,软件自身常常可以自行处理一切工作,用户只需点击几下软件中的‘主要’按钮.不过,有时要想获得更好的质量结果,或者解决某个不寻常的 ...
- Centos修改时间显示的时区,将UTC修改为CST
问题说明: 今天一同事反应,系统的时间不对和正常的时间差8个小时.就登录主机看了下时间 系统时间显示为: # date Fri Dec :: UTC # 备注:查看了下,正好和当前的时间差了8个小时. ...
- flume 增量上传日志文件到HDFS中
1.采集日志文件时一个很常见的现象 采集需求:比如业务系统使用log4j生成日志,日志内容不断增加,需要把追加到日志文件中的数据实时采集到hdfs中. 1.1.根据需求,首先定义一下3大要素: 采集源 ...
- (翻译)2016美国数学建模MCM F题(政策)翻译:难民移民政策建模
PROBLEM F:Modeling Refugee Immigration Policies With hundreds of thousands of refugees moving across ...