原型链可以说是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 原型链的更多相关文章

  1. [js高手之路]一步步图解javascript的原型(prototype)对象,原型链

    我们接着上文继续,我们通过原型方式,解决了多个实例的方法共享问题,接下来,我们就来搞清楚原型(prototype),原型链的来龙去脉. function CreateObj(uName) { this ...

  2. [js高手之路]原型对象(prototype)与原型链相关属性与方法详解

    一,instanceof: instanceof检测左侧的__proto__原型链上,是否存在右侧的prototype原型. 我在之前的两篇文章 [js高手之路]构造函数的基本特性与优缺点 [js高手 ...

  3. 对Javascript 类、原型链、继承的理解

    一.序言   和其他面向对象的语言(如Java)不同,Javascript语言对类的实现和继承的实现没有标准的定义,而是将这些交给了程序员,让程序员更加灵活地(当然刚开始也更加头疼)去定义类,实现继承 ...

  4. 图解JavaScript中的原型链

    转自:http://www.jianshu.com/p/a81692ad5b5d typeof obj 和 obj instanceof Type 在JavaScript中,我们经常用typeof o ...

  5. 原型prototype、原型链__proto__、构造器constructor

    创建函数时,会有原型prototype,有原型链__proto__,有constructor.(构造函数除外,没有原型) . prototype原型:是对象的一个属性(也是对象),使你有能力向对象添加 ...

  6. JavaScript之基于原型链的继承

    本文介绍下js的OOP中的继承. 上图的要点为:Foo函数在创建时会自动生成内置属性prototype,而typeof Foo.prototype是object类型的. 上图的要点为:Foo.prot ...

  7. 一张图搞懂 Javascript 中的原型链、prototype、__proto__的关系 转载加自己的总结

    1. JavaScript内置对象 所谓的内置对象 指的是:JavaScript本身就自己有的对象 可以直接拿来就用.例如Array String 等等.JavaScript一共有12内置对象    ...

  8. Javascript中的原型链、prototype、__proto__的关系

    javascript  2016-10-06  1120  9 上图是本宝宝用Illustrator制作的可视化信息图,希望能帮你理清Javascript对象与__proto__.prototype和 ...

  9. JavaScript继承与原型链

    对于那些熟悉基于类的面向对象语言(Java 或者 C++)的开发者来说,JavaScript 的语法是比较怪异的,这是由于 JavaScript 是一门动态语言,而且它没有类的概念( ES6 新增了c ...

随机推荐

  1. [源码解析] PyTorch如何实现前向传播(3) --- 具体实现

    [源码解析] PyTorch如何实现前向传播(3) --- 具体实现 目录 [源码解析] PyTorch如何实现前向传播(3) --- 具体实现 0x00 摘要 0x01 计算图 1.1 图的相关类 ...

  2. SDIO总线协议

    SDIO采用HOST-DEVICE模式,所有通信都由HOST端发命令,DEVICE设备只要解析HOST命令就可与HOST进行通信. SDIO总线的几根线: 1.  CLK信号:HOST给DEVICE的 ...

  3. linux 内核源代码情景分析——用户堆栈的扩展

    上一节中,我们浏览了一次因越界访问而造成映射失败从而引起进程流产的过程,不过有时候,越界访问时正常的.现在我们就来看看当用户堆栈过小,但是因越界访问而"因祸得福"得以伸展的情景. ...

  4. 让Visual Studio x64 支持 __asm内联汇编

    目录 让Visual Studio x64 支持 __asm内联汇编 Intel Parallel Studio XE 2016安装 设置Interl C++ Compiler 使VS x64支持内联 ...

  5. Linux下向windows传输文件【sz 文件】没有弹框提示下载到什么位置

    Linux环境向windows环境传输文件 security crt工具,同同一个软件,连接不同服务器,有的服务器传送文件没有弹框选择要下载的文件路径,可以在[Options]-[Session Op ...

  6. Vulnstack内网靶场4

    环境 漏洞详情 (qiyuanxuetang.net) 仅主机模式内网网段192.168.183.0/24 外网网段192.168.157.0/24 其中Ubuntu作为对外的内网机器 攻击机kali ...

  7. QuantumTunnel:协议路由 vs 端口路由

    本篇来聊一下内网穿透中流量转发的问题 内网穿透和核心逻辑是根据流量的路由信息准确地将公网流量路由到指定的机器端口上,从而完成一次流量的内网穿透. 这里有一个核心问题,路由信息从哪里获取? 常见的有将路 ...

  8. go的常用数据类型-持续优化篇

    p.p1 { margin: 0; font: 12px "Helvetica Neue"; color: rgba(69, 69, 69, 1) } p.p2 { margin: ...

  9. 《手把手教你》系列技巧篇(四十一)-java+ selenium自动化测试 - 处理iframe -上篇(详解教程)

    1.简介 原估计宏哥这里就不对iframe这个知识点做介绍和讲解了,因为前边的窗口切换就为这种网页处理提供了思路,另一个原因就是虽然iframe很强大,但是现在很少有网站用它了.但是还是有小伙伴或者童 ...

  10. Spark中资源调度和任务调度

    Spark比MR快的原因 1.Spark基于内存的计算 2.粗粒度资源调度 3.DAG有向无环图:可以根据宽窄依赖划分出可以并行计算的task 细粒度资源调度 MR是属于细粒度资源调度 优点:每个ta ...