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

原型链对于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. ubuntu下caffe配置

    http://blog.csdn.net/yhaolpz/article/details/71375762

  2. 《精通Spring4.X企业应用开发实战》读后感第四章(Application中Bean的生命周期)

    package com.smart.beanfactory; import org.springframework.beans.BeansException; import org.springfra ...

  3. 3、opencv 图像显示功能

    #include <iostream>#include <opencv2/opencv.hpp>using namespace cv;using namespace std;i ...

  4. UVaLive 4094 WonderTeam (贪心)

    题意:有n支队伍,每两支队伍打两场比赛(主客场各一次),胜得3分,平得1分,输不得分,比赛结束之后会评选出一个梦之队, 梦之队满足以下条件:进球总数最多,胜利场数最多,丢求总数最少,三个都不能并列,求 ...

  5. matlab新手入门(四)(翻译)

    工作空间变量 工作区包含您在数据文件或其他程序中创建或导入到MATLAB®中的变量. 例如,这些语句在工作空间中创建变量A和B. A=255; b=ones(size(Img)); 您可以使用whos ...

  6. js基础(补10.10)

    1.内嵌式: <html> <head> <title></title> </head> <body> <a href=& ...

  7. 数据库路由中间件MyCat - 源代码篇(14)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 对于表的dataNode对应关系,有个特殊配置即类似dataNode="distributed(d ...

  8. CentOS 下部署Nginx+Gunicorn+Supervisor部署Flask项目

    原本之前有一部分东西是在Windows Server,但是由于Gunicorn不支持Windows部署起来颇为麻烦.最近转战CentOS,折腾一段时间,终于简单部署成功.CentOS新手,作为一个总结 ...

  9. Git 分支管理 多人协作 远程仓库 补充

    当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了, 并且,远程仓库的默认名称是origin. 如果是本地仓库关联远程仓库 --- 要查看远程库的信息,用 ...

  10. (转)深度学习(Deep Learning, DL)的相关资料总结

    from:http://blog.sciencenet.cn/blog-830496-679604.html 深度学习(Deep Learning,DL)的相关资料总结 有人认为DL是人工智能的一场革 ...