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

原型链对于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. HDU-5980

    Find Small A Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  2. 滴滴Booster移动APP质量优化框架 学习之旅

    推荐阅读: 滴滴Booster移动App质量优化框架-学习之旅 一 Android 模块Api化演练 不一样视角的Glide剖析(一) 一.Booster简介 Booster是滴滴最近开源一个的移动应 ...

  3. HTML5学习笔记(一)相关概率

    HTML5的设计目的是为了在移动设备上支持多媒体. 声明:<!DOCTYPE html> 注意:对于中文网页需要使用 <meta charset="utf-8"& ...

  4. ue4 碰撞检测测试

    记录几条物理相关 测试条件,1使用setActorLocation移动,3使用控制器的移动 1 moveCube  2 targetCube  3 Character 两个Cube的碰撞事件 1和2的 ...

  5. 洛谷P3182 [HAOI2016]放棋子

    P3182 [HAOI2016]放棋子 题目描述 给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要 ...

  6. IT兄弟连 JavaWeb教程 jQuery对AJAX的支持

    jQuery对AJAX的支持 jQuery对Ajax请求的创建.发送.响应.注册数据处理函数.JSON的解析和缓存以及传参等都进行了相应的封装,同时也考虑了浏览器的兼容性问题. jQuery中对AJA ...

  7. SpringBoot(1)—启动原理之SpringApplication对象的创建

    创建SpringApplication对象 SpringBoot版本为 2.1.1.RELEASE @SpringBootApplication public class SpringbootDemo ...

  8. HDMI和VGA接口

    HDMI英文全称为:High Definition Multimedia Interface,它是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号. HDMI接口与VGA接口区别如下: ...

  9. C 语言实例 - 输出九九乘法口诀表

    C 语言实例 - 输出九九乘法口诀表 使用嵌套 for 循环输出九九乘法口诀表. 实例 #include<stdio.h> int main(){ //外层循环变量,控制行 ; //内层循 ...

  10. Ajax案例:异步加载后台订单详情信息