全面了解 Javascript Prototype Chain 原型链
原型链可以说是Javascript的核心特征之一,当然也是难点之一。学过其它面向对象的编程语言后再学习Javascript多少会感到有些迷惑。虽然Javascript也可以说是面向对象的语言,但是其实现面向对象是通过prototype-based的机制而不是class-based机制。它没有其它面向对象语言的继承,多态等,但是我们却可以通过prototype来实现继承。
下面我就带大家来了解一下原型链
原型链初接触
之前写过《你理解Javascript的闭包吗》这篇文章,在介绍闭包的时候首先是从其名字开始介绍的,通过名字大概了解其涉及的知识点。同样在这我们也先从这个名字开始谈起。
原型链,可以分成两部分——原型和链。
链
对于Javascript,可以看作是一个自上而下的链式结构。(如果对Javascript基础知识比较欠缺,可以参考 Javascript 教程)我们来看这样的一个例子
例一
function func(){
this.a = '1';
this.b = '2';
}
func.prototype.b='3';
func.prototype.c='4';
var f = new func();
console.log(f.a);
console.log(f.b);
console.log(f.c);
对于这个例子先用下图表示其各属性之间的关系
图一
此种链式结构首先会查找func()实例化对象,没有找到要找的数据的话就会再去查找其原型Prototype。所以我们来看上面的例子,f.a在对象f中存在,所以直接打印为1;f.c在对象f中不存在,所以再去查找原型Prototype,所以c打印为4;对于f.b,在对象f和原型Prototype中都存在,但是按照其查找顺序,首先找到的是对象f中的b,所以就直接打印为2。这就是Javascript链式结构的查找机制。
那对于Prototype中的b岂不是就浪费了,对于Prototype中的b我们稍后会解释它在什么情况下会被用到。
下面我们再来看一下原型的概念。
原型
对于原型——也就是Prototype,指的是生成对象的那个方法。在其他编程语言中我们可以理解成类,而Prototype可以认为是static静态属性,它是属于类而不是属于对象的,但是其又可以被对象调用。
既然叫原型,那它肯定是在类下面而不是对象,所以对于上例来说我们可以写成func.prototype.c = ‘4’ 却不可以写成 f.prototype.c = ‘4’,后者是有语法错误的,js调试器会报f.prototype is undefined错误。也就是说f.prototype是错误的,当然也不能说是错误,f.prototype可以看成是prototype是对象f的一个属性,和f.a、f.b没有任何的区别。
所以说从名称上面我们就可以大概了解其原理,从而避免一些不必要的错误。
原型链
上面分别介绍了原型和链两个概念以后,现在我们将二者结合起来看一下原型链以及如何构造一个原型链。
我们可以这样认为,Javascript对象就是一个属性包(当然这些属性都是其自身的属性),并且对象本身还有一条指向其原型的链。当试图访问对象的某个属性的时候,它不仅仅在对象本身查找,还会去对象指向的原型上面去查找,以及该对象原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性抑或是达到原型链的末尾。
还记得上面例一中提到的func.prototype.b这个属性吗,我们对例一进行一下改造
例二
function func(){
this.a = '1';
this.b = '2';
}
func.prototype.b = '3';
func.prototype.c = '4';
var f = new func(); function func2(){
this.d = '5';
}
func2.prototype = Object.create(func.prototype);
func2.prototype.c = '6';
var f2 =new func2();
console.log(f.a);
console.log(f2.b);
console.log(f2.d);
console.log(f2.c);
console.log(f.c);
对于这个例子,我们先用一张图来表示其各部分关系
图二
结合上图按照Javascript访问某个对象属性的查找顺序我们可以推出上面各个值。
f.a 毫无疑问值为1;f2.b首先会查找对象f2,没有此属性然后再去查找其原型依然没有,接着再去查找其原型所指的原型发现b=3,所以f2.b打印值为3;f2.d 值为5,这个没有什么疑问;我们先说f.c,它和例一中的情况是一样的,在f对象所指的原型中定义为4,所以在本例中同样f.c的值为4;最后是f2.c,我们看f2的原型指向了f的原型,但是在下面有对f2的原型func2.prototype中的属性c进行了定义即func2.prototype.c=6 所以说f2.c首先在f2的原型中被找到从而打印出来,并不会继续向上一层找,所以f2.c打印值为6,如果说将func2.prototype.c=6注释掉,那f2.c的值其实就是f对象所指原型中的c的值了,也就是4;那虽然说f2的原型指向了f的原型,那对f2的原型增加属性会不会影响f的原型,答案是否定的,也就是说f指向的原型不会受影响。因为我们可以看作是Object.create(func.prototype)实例化了一个f指向的原型的一个对象并将其赋值给f2的原型,所以f的原型本身是不会受影响的。这一点从f.c的值也可以看出来,如果受影响的话那f.c的值不就成了6了吗,可是事实却不是这样的。
通过这个例子相信大家对原型链的概念应该有一个基本的认识吧!
原型链实际应用
我们可以使用原型链来模拟面向对象编程语言中的继承,例子如下
例三
function Action(){
this.pro1 = 'a';
}
Action.prototype = {
pro2:'b',
operate:function(){
console.log('action');
}
}
function IndexAction(){
this.pro1 = 'b';
}
IndexAction.prototype = Object.create(Action.prototype);
var index = new IndexAction();
index.operate();
这个例子可以看成是一个简单的继承关系,其中Action中的pro1是其私有的属性,不会被IndexAction所继承,但是其pro2和方法operate会被继承。而IndexAction中的pro2也是其自己的私有属性。
当然原型链还有在其他方面的应用,这里我们就举一个继承的例子来供大家理解。
原型链的性能
当访问某一对象的属性时,在原型链上查找该属性时比较费时间的,这堆性能有比较坏的影响。这在对性能要求比较苛刻的情况下是比较重要的。除此之外,当我们访问一个不存在的属性的时候,Javascript会遍历整个原型链。因此我们在用原型编写复杂代码前充分了解原型继承的构造是非常有必要的,并且掌握自己代码中原型链的长度在必要的时候结束原型链从而避免上面提到的性能问题。
此外对于Javascript中原生对象的原型不要在上面进行新功能的扩展,除非是为了Javascript的兼容性。
例如
Object.prototype = {
pro:”pro”,
operate:function(){}
}
Object是Javascript中原生的对象,我们要尽量避免上述代码出现在我们的程序中。
总之,对于原型链我们应该多在编程过程中去理解,否则即使当时明白,经过一段时间不去写代码的话慢慢的我们也就会淡忘。
全面了解 Javascript Prototype Chain 原型链的更多相关文章
- [js高手之路]一步步图解javascript的原型(prototype)对象,原型链
我们接着上文继续,我们通过原型方式,解决了多个实例的方法共享问题,接下来,我们就来搞清楚原型(prototype),原型链的来龙去脉. function CreateObj(uName) { this ...
- [js高手之路]原型对象(prototype)与原型链相关属性与方法详解
一,instanceof: instanceof检测左侧的__proto__原型链上,是否存在右侧的prototype原型. 我在之前的两篇文章 [js高手之路]构造函数的基本特性与优缺点 [js高手 ...
- 对Javascript 类、原型链、继承的理解
一.序言 和其他面向对象的语言(如Java)不同,Javascript语言对类的实现和继承的实现没有标准的定义,而是将这些交给了程序员,让程序员更加灵活地(当然刚开始也更加头疼)去定义类,实现继承 ...
- 图解JavaScript中的原型链
转自:http://www.jianshu.com/p/a81692ad5b5d typeof obj 和 obj instanceof Type 在JavaScript中,我们经常用typeof o ...
- 原型prototype、原型链__proto__、构造器constructor
创建函数时,会有原型prototype,有原型链__proto__,有constructor.(构造函数除外,没有原型) . prototype原型:是对象的一个属性(也是对象),使你有能力向对象添加 ...
- JavaScript之基于原型链的继承
本文介绍下js的OOP中的继承. 上图的要点为:Foo函数在创建时会自动生成内置属性prototype,而typeof Foo.prototype是object类型的. 上图的要点为:Foo.prot ...
- 一张图搞懂 Javascript 中的原型链、prototype、__proto__的关系 转载加自己的总结
1. JavaScript内置对象 所谓的内置对象 指的是:JavaScript本身就自己有的对象 可以直接拿来就用.例如Array String 等等.JavaScript一共有12内置对象 ...
- Javascript中的原型链、prototype、__proto__的关系
javascript 2016-10-06 1120 9 上图是本宝宝用Illustrator制作的可视化信息图,希望能帮你理清Javascript对象与__proto__.prototype和 ...
- JavaScript继承与原型链
对于那些熟悉基于类的面向对象语言(Java 或者 C++)的开发者来说,JavaScript 的语法是比较怪异的,这是由于 JavaScript 是一门动态语言,而且它没有类的概念( ES6 新增了c ...
随机推荐
- 【JAVA】【作业向】第一题:本学期一班级有n名学生,m门课程。现要求对每门课程的成绩进行统计:平均成绩、最高成绩、最低成绩,并统计考试成绩的分布律。
1.预备知识:动态数组Array实现: 2.解题过程需要理解的知识:吧唧吧唧吧唧吧唧 不想做了 就用了最简单的方法 和c语言类似 java版本 `import java.util.Scanner; / ...
- Golang通脉之包的管理
在工程化的开发项目中,Go语言的源码复用是建立在包(package)基础之上的. 包(package)是多个Go源码的集合,是一种高级的代码复用方案,Go语言提供了很多内置包,如fmt.os.io等. ...
- WPF实现雷达图(仿英雄联盟)
WPF开发者QQ群: 340500857 | 微信群 -> 进入公众号主页 加入组织 前言 有小伙伴提出需要实现雷达图. 由于在WPF中没有现成的雷达图控件,所以我们自己实现一个. PS:有更 ...
- JDK里常见容器总结
自己总结. 扩容 线程安全 是否支持null 的key 说明 hashmap 2*length 否 是 1.8以后增加红黑树.提高检索效率 hashtable 是 否 官方不建议使 ...
- 浅析ReDoS的原理与实践
转载于http://www.freebuf.com/articles/network/124422.html ReDoS(Regular expression Denial of Service) 正 ...
- BUAA软工-结对项目作业
结对项目作业 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结对项目作业 我在这个课程的目标是 通过这门课锻炼软件开发能力和经验,强化与他人合作 ...
- 认识Linux系统中的inode,硬链接和软链接
在学习和创建软链接遇到了一点问题,总结一下: 在当前文件夹下面建立了两个临时文件夹tempdir1和tempdir2,然后在tempdir2里面创建了一个hello文件,然后用指令ln -s temp ...
- linux 文件描述符和inode 的理解和区别
inode 或i节点是指对文件的索引.如一个系统,所有文件是放在磁盘或flash上,就要编个目录来说明每个文件在什么地方,有什么属性,及大小等.就像书本的目录一样,便于查找和管理.这目录是操作系统需要 ...
- VSCode Java 开发环境配置 详细教程
VSCode Java 开发环境配置 详细教程 配置java 下载 用于现在大多数使用者用的是java 8,小白的我先安装java 8好了,^ w ^. 下载地址:Java 8 | Java SE 打 ...
- docker容器运行java后台程序,存到数据库的时间差一天的问题
主要原因是docker容器中的时间用的是标准时间,不是用的宿主机的时间. 修改方法: docker run -e TZ="Asia/Shanghai" -d -p 80:80 -- ...