夜深风竹敲秋韵,万叶千声皆是恨。

原型链对于JavaScript来说是个很核心的概念。JavaScript不是基于类模板的面向对象语言;反而,它的面向对象机制是基于原型的。我们不可能说某个对象属于什么类,但却可以得到某个对象的原型对象。原型对象相当于一个父级代理,当属性在某个对象中找不到时,就会委托该对象的原型去查找。

原型链的基础

JavaScript的每个对象,都可以有一个隐式的链接(名为__proto__),指向它的原型对象。这次,我冒天下之大不韪(__proto__是私有属性,不能直接对它进行操作),显示地定义几个对象和它们的原型关系。

a = {k1: 'a1'};
b = {k1: 'b1', k2: 'b2'};
c = {k1: 'c1', k2: 'c2', K3: 'c3'}; a.__proto__ = b;
b.__proto__ = c;
c.__proto__ = undefined;

上面的例子中,我们首先定义了三个对象a,b,c。接下来构造它们的原型关系。其中a的原型是b,b的原型是c,c没有原型。a、b、c形成了一条链式结构,这条链式结构在c处终止。这样一条链式结构就是原型链。

原型链的作用主要在于对象的取值操作。当我们根据属性名从对象中取值时,首先会在当前对象中查找。如果在当前对象中查找不到,就会上升到该对象的原型中继续查找。如果仍然查找不到,就会继续上升到原型的原型……这个过程会一直持续下去,直到在某一次查找到或者原型链终止。所以下面的返回结果是显然的:

a.k1 //=> 'a1'
a.k2 //=> 'b2'
a.k3 //=> 'c3'
a.k4 //=> undefined

然而对象的设值和删值就不会参考原型链了,它只是对当前对象的操作。下面的例子具有一定的启发性:

delete a.k2 //无效,a中没有k2属性
a.k2 //=> 'b2'
a.k2 = 'a2' //只会影响对象a,不会影响对象b
a.k2 //=> 'a2'
delete a.k2 //有效,删除a的k2属性
a.k2 //=> 'b2' a的k2属性被删除,b的k2属性暴露了出来

原型链的作用

原型链的作用主要有以下两个方面。

将共享属性和方法放到原型中去

如果多个对象共享一些属性和方法,那就让这些对象指向同一个原型,在原型中定义这些属性和方法。这样共享的属性和方法只用在原型处一次定义,而无需在每个对象中重复定义。

继承

当对象a想要继承b的属性和方法时,只需简单地将b定义为a的原型即可。

关于继承,还有一点补充。除了原型继承之外,将对象b的属性和方法拷贝到a中去也能实现继承。这里b的属性和方法就直接存在于a中,而不是通过原型获取。

构造器函数与原型链

构造器函数可以帮助我们构建原型链。构造函数的特色如下:

//一般构造器函数首字母大写
function Foo(name) {
this.name = name;
//一般不用返回任何值
}

构造器函数中,this绑定的是一个新建的对象,并且函数默认会返回这个对象。当定义构造器函数时,不要显示地返回一个值,除非你知道自己是在做什么。

每个函数都有一个名为prototype链接,它指向一个对象。当函数作为普通函数调用时,这个链接没什么用处。只有当它作为一个构造器函数调用时,它才与原型链构成联系。其实很简单,构造器函数新建的对象,其原型就是该函数的prototype链接的对象。所以一定有下面的关系:

new Foo().__proto__ === Foo.prototype;

关于属性共享和继承的策略,可以对应到构造器函数中去。由于Foo.prototype就是new Foo()的原型,所以将共享属性和方法放到Foo.prototype中去就可以了。

function Foo(name) {
this.name = name; //对象的示例属性要绑定到this上
} //对象的共享属性和方法绑定到Foo.prototype上
Foo.prototype.attr = 'attr';
Foo.prototype.foo = function() {};

继承的实现其实有很多种方式,但很难找出直接的方式。例如我们有构造器函数A,B,C,现在想要C继承自B,B继承自A,可以通过下面的方式实现:

function A() {}
function B() {}
function C() {} A.prototype = new B();
B.prototype = new C();

不是很直观,但确实做到了继承。老实说,这不是最好的方式,因为中间对象采用new B()和new C()的方式构造,将B和C的实例变量引入到了原型链中来了。

ES5中有关原型链的函数

为了行文上的方便,我在上面多处提到了__proto__。但是不要通过__proto__隐式链接去处理原型,__proto__不是JavaScript的标准,不同浏览器对于它们有不同的解释。也就是说,我们不能像下面这样做:

a.__proto__ = b; //=>不能像这样构造原型关系
a.__proto__; //=>不能像这样得到对象的原型

ES5(EMCAScript5)中Object对象增加了两个新的方法,分别是create和getPrototypeOf,分别实现上面的两种效果。上面的例子就可以像下面这样改写了。

a = Object.create(b);     //返回一个以b作为原型的新对象
Object.getPrototypeOf(a); //返回a的原型对象

方法参考:

(四)我的JavaScript系列:原型链的更多相关文章

  1. javaScript系列 [04]-javaScript的原型链

    [04]-javaScript的原型链 本文旨在花很少的篇幅讲清楚JavaScript语言中的原型链结构,很多朋友认为JavaScript中的原型链复杂难懂,其实不然,它们就像树上的一串猴子. 1.1 ...

  2. JavaScript的原型链继承__propt__、prototype、constructor的理解、以及他们之间相互的关系。

    回想自己已经工作了有一段时间了,但是自己对JavaScript的原型链.和继承的理解能力没有到位,最近他们彻底的整理并且复习了一遍. 本案例中部分文案来自网络和书籍,如有侵权请联系我,我只是把我的理解 ...

  3. Javascript的原型链图

    90%的前端或者js程序员或者老师们对Javascript懂得不比这个多 给手机看的 但是这个图里的所有褐色单向箭头链就是Javascript的原型链(颜色标注对理解js原型链很关键) 这图中的各个_ ...

  4. javascript prototype原型链的原理

    javascript prototype原型链的原理 说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: <script type="text/javasc ...

  5. javaScript(原型链)

    在了解javaScript的原型链之前,我们得先来看一下原型是什么. 在javaScript中,所有的函数都会有着一个特别属性:prototype(显示原型属性):当我们运行如下代码时: functi ...

  6. 理解JavaScript的原型链

    1. 什么是对象 在JavaScript中,对象是属性的无序集合,每个属性存放一个原始值.对象或函数. 1.1 创建对象 在JavaScript中创建对象的两种方法: ① 字面上: var myObj ...

  7. JavaScript扩展原型链浅析

    前言 上文对原型和原型链做了一些简单的概念介绍和解析,本文将浅析一些原型链的扩展. javaScript原型和原型链 http://lewyon.xyz/prototype.html 扩展原型链 使用 ...

  8. javascript的原型链那些事

    如果你对javascript的原型链还有任何疑问,请看这篇文章 进入主题 前言 原型链的规则不百分百适用于所有情况 显式原型:prototype,是一个对象{} 隐式原型:__proto__,是一个对 ...

  9. javascript基础学习系列-原型链模式

    1.demo代码如下: 2.画图如下: 3.规则: 1)每一个函数数据类型(普通函数/类)都有一个天生自带的属性:prototype(原型),并且这个属性是一个对象数据类型的值 2)并且prototy ...

  10. javascript总结系列49:javaScript教程:原型链不可变

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...

随机推荐

  1. grep的用法(CentOS7)及有关正则表达式的使用

    环境准备:alias grep="grep --color" 1.grep以整行为单位进行处理,行中有的匹配显示出来 Last中取出符合root的行:grep  '查找字符串' l ...

  2. 转-tcp建立和释放详解

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. [更新于2017.01.04 ]该部分内容配图有误,请大家见谅,正确的配图如下,错误配图也不删 ...

  3. 远程访问Linux系统桌面

     让Windows可以远程访问Linux系统桌面 http://jingyan.baidu.com/article/d8072ac47b810eec95cefde8.html linux系统下,11款 ...

  4. 测试你开发的web系统在各种类型浏览器上的兼容性

    可以使用 https://www.browserstack.com 来测试你所开发的web系统在各种各样的浏览器,以及各种手机平台上的兼容性.

  5. HDU - 5887 2016青岛网络赛 Herbs Gathering(形似01背包的搜索)

    Herbs Gathering 10.76% 1000ms 32768K   Collecting one's own plants for use as herbal medicines is pe ...

  6. MVC4 @helper辅助方法

    Razor提供了一种很方便的语法,可以将view页面中部分内容或部分代码抽取出来,变成一个独立的辅助方法.   eg1: @foreach(var item in Model){ <标签tr&g ...

  7. 大话Spark(1)-Spark概述与核心概念

    说到Spark就不得不提MapReduce/Hadoop, 当前越来越多的公司已经把大数据计算引擎从MapReduce升级到了Spark. 至于原因当然是MapReduce的一些局限性了, 我们一起先 ...

  8. bzoj 4788: [CERC2016]Bipartite Blanket【hall定理+状压】

    考虑当前合法的一个点集s,如果他合法,那么一定有一个完备匹配的点集包含这个点集,也就是两边都满足hall定理的话这两边拼起来的点集也满足要求 所以分别状压两边点集用hall定理转移判断当前点集是否合法 ...

  9. SonarQube总结

    官网:https://www.sonarqube.org/ 一款代码质量管理开源平台.

  10. 解决lnmp无法远程登录的bug

    使用lnmp一键安装好linux环境后,不能远程连接到所在服务器的mysql,但是通过80端口可以登录phpmyadmin,发现原来是因为lnmp的大多数版本为了安全不禁止远程连接mysql,方法很简 ...