原型链可以说是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. Kubernetes-Service介绍(三)-Ingress(含最新版安装踩坑实践)

    前言 本篇是Kubernetes第十篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战. Kubernetes系列文章: Kubernetes介绍 Kubernetes环境搭建 Kuberne ...

  2. silky微服务快速开始

    项目介绍 Silky框架旨在帮助开发者在.net平台下,通过简单代码和配置快速构建一个微服务开发框架. Silky 通过 .net core的主机来托管微服务应用.通过 Asp.Net Core 提供 ...

  3. LeetCode:动态规划

    动态规划 动态规划永远的神 这部分主要是学习了 labuladong 公众号中对于动态规划的讲解 刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 题目 这部分内容直接上题目了,解题 ...

  4. netty入门实现简单的echo程序

    最近看以往在程序中编写的代码,发现有一个功能是使用socket通讯来实现的,而那个时候使用的是基于bio的阻塞io来实现的,最近在看netty,发现可以使用netty来使用nio的方式来实现,此博客记 ...

  5. 请问为什么要用三极管驱动mos,直接用mos有什么缺点呢?

    可能无法完全导通,电流可能过小使导通所需时间变长,最终导致发热严重       回复 举报     csaaa DIY七级 3# 发表于 2016-7-12 14:11:59 直接驱动mos也没什么问 ...

  6. 从零开始的DIY智能家居 - 基于 ESP32 的智能水浊度传感器

    前言 家里有个鱼缸养了几条鱼来玩玩,但是换水的问题着实头疼,经常一个不注意就忘记换水,鱼儿就没了.o(╥﹏╥)o 在获得 Spirit 1 边缘计算机 后就相当于有了一个人智能设备服务器,可以自己开发 ...

  7. 手把手搭建自己的智能家居 - 基于 IOT Pi 的智能甲醛检测器

    智慧家居 - 基于 IOT Pi 的智能甲醛检测器 之前的文章体验 MS-RTOS 的时候入手了一个块 IOT Pi ,放着也是浪费,这次我们就利用 IOT PI 开发一个智能甲醛检测器.φ(> ...

  8. cf17B Hierarchy(额,,,水)

    题意: Nick's company employed n people. Now Nick needs to build a tree hierarchy of «supervisor-surbod ...

  9. hdu 2955 Robberies(背包DP)

    题意: 小偷去抢银行,他母亲很担心. 他母亲希望他被抓的概率真不超过P.小偷打算去抢N个银行,每个银行有两个值Mi.Pi,Mi:抢第i个银行所获得的财产 Pi:抢第i个银行被抓的概率 求最多能抢得多少 ...

  10. Linux安装部署Zabbix

    Zabbix 是一个企业级的分布式开源监控方案,能够监控各种网络参数以及服务器健康性和完整性的软件.Zabbix使用灵活的通知机制,允许用户为几乎任何事件配置基于邮件的告警.这样可以快速反馈服务器的问 ...