javascript  2016-10-06  1120  9

上图是本宝宝用Illustrator制作的可视化信息图,希望能帮你理清Javascript对象与__proto__、prototype和原型链之间的关系。如果暂时看不懂也没关系,这篇文章让你从0变成1。

0、感性认识JS里的“德罗斯特效应”之原型链

如果你打开浏览器的控制面板,随便输入一个JS内置的构造器函数,比如Array,控制台输出的是一个名为Array的函数体,这好像并没有什么稀奇的,但是,当你接着输入Array.prototype,控制面板输出了一堆我们经常用到的Array构造器的方法,把目光转移到最下方,有一个叫__proto__的属性,好奇的点开,

咦~?列表列出的不是Object构造器的方法么,里边有我们非常熟悉的hasOwnProperty还有toString等方法。我们常说的一切皆对象,一切对象皆null这么玄妙的编程界哲理和这种嵌套会不会有什么关系呢?更神奇的在下边。

继续深入思考,Array是构造器,那么控制台输出的Array.prototype的所有属性中的constructor(翻译:构造器)又是指向什么?点开看看,之后就像身处德罗斯特效应中一样,__proto__和constructor,还有Array构造器中常用的方法名不断的出现,一层套一层,一层层展开,没有尽头。。。

一、满满一堂证明题课

当你也发现了JS里这种循环往复、不断嵌套的规律后,仍然不相信自己的眼睛,于是决定亲自证明一下,哦不,是好几下。(对于初学者只靠空想太烧脑,于是本宝宝做了几个GIF动图。)

1、怎么证明你就是你?

这个问题可难不倒JS中的构造器们,一个证明秒秒钟证明“我就是我”,是颜色不一样的烟火。

拿Array举例,Array.prototype中有一个constructor属性,这个属性的值就是Array构造器自己!

2、“遗传进化链__proto__”,怎么证明一切皆对象?

所有的JS内置构造器都本是对象,这要从long long ago说起。可是从什么线索开始向过去前进呢,原型链(我给他起了一个名字叫遗传进化链)就是突破口。所有JS构造器(当然不止构造器有)都有一个__proto__属性,这是原型链指针,指向进化成它的“那个”。(就像我的__proto__指针指向我父母,我父母各自的__proto__指向他们的父母... ...鬼知道最尽头的Ta经历了什么!?(手动黑人问号脸)。在进化的过程中,父母的遗传物质(属性、方法)被我的__proto__指针引用着,同时我也变异出了自己的能力(属性、方法),然后我的子代的__proto__指针又引用我的遗传物质。额!为毛突然莫名脸红~)

从上图中发现,JS内置构造器其中之一的Array原本就是一个函数,而这个函数就是Function的prototype,所以Function.prototype有的方法,JS内置构造器都有,比如call()、apply()、bind()等(其实我们自定义的函数也是继承自Function.prototype,所以我们自己也可以定义构造器,创造属于自己的小小王国)。(所以在编程的世界里模拟一个宇宙系统是有可能的,说不定我们本来就生活在被设定好的编程世界里哦。)

而Function.prototype的进化链指针又指向了Object.prototype。

3、怎么证明到头来一切都是空?

不管你从那个属性开始,连续引用__proto__的指针,最后输出的那个值就是null。

上图中,一时手残,打成大写的P了。

万物都是从无生出来的?!Hi boy 老聃的道德经han庄子 读多了吧

4、怎么证明所有JS内置构造器和自定义函数都是Function构造器的原型(prototype)。

不断强化这一认知,实践出真知。

①、String构造器的进化链指针__proto__指向Function构造器的原型

//String构造器
String.__Proto__ === Function.prototype

②、Number构造器的进化链指针__proto__指向Function构造器的原型

//Number构造器
Number.__Proto__ === Function.prototype

③、Boolean构造器的进化链指针__proto__指向Function构造器的原型

//Boolean构造器
Boolean.__Proto__ === Function.prototype

④、Array构造器的进化链指针__proto__指向Function构造器的原型

//Array构造器
Array.__Proto__ === Function.prototype

⑤、没错,Function构造器的进化链指针__proto__也指向自己的原型

//Function构造器
Function.__Proto__ === Function.prototype

⑥、Date构造器的进化链指针__proto__指向Function构造器的原型

//Date构造器
Date.__Proto__ === Function.prototype

⑦;、Error构造器的进化链指针__proto__指向Function构造器的原型

//Error构造器
Error.__Proto__ === Function.prototype

⑧、Object构造器的进化链指针__proto__指向Function构造器的原型

//Object构造器
Object.__Proto__ === Function.prototype

⑨、RegExp构造器的进化链指针__proto__指向Function构造器的原型

//RegExp构造器
RegExp.__Proto__ === Function.prototype

⑩、Event构造器的进化链指针__proto__指向Function构造器的原型

//Event构造器
Event.__Proto__ === Function.prototype

这里需要注意所有构造器的prototype都是对象(object)类型,只有Function.prototype是函数(function)类型,这是为了保证函数构造器们的__proto__指向的都是函数。

二,咦?JSON和Math哪去啦?

JS内置的构造器函数都可以使用new关键字实例化一个对象,我们称实例化后的这个对象就是某某构造器的一个实例。就像我们每一个“人”都是“人类”这个构造器函数的一个实例

//实例化一个String构造函数
var str = new String("Hi, today! ");

既然上边10个构造器函数都能这样实例化对象,那么JSON和Math是不是也可以用new 关键字实例化呢?试试看!

//尝试实例化JSON和Math两个构造器函数
var json = new JSON();
var Math = new Math();

哦No,不可以。JSON和Math不是构造器函数,他们是普通的对象。

上边提到过,只有构造器函数才能使用new 关键字实例化一个对象,而JSON和Math已经是对象了,所以我们可以不用实例化直接使用JSON和Math中的属性和方法~~(我们实例化的目就是想用实例化后的对象里的属性和方法,那么既然JSON和Math已经是对象了,就省去实例化的操作喽。当然,能实例化有能实例化的好处~)

所以JSON和Math不属于10个构造器函数,但他们12个共同属于Javascript的内置对象。

三、__proto__进化链指针设计为什么如此重要!!

javascript中为什么会有__proto__原型链的设计,不防做一个小实验先。

//实例化一个String对象
var str = new String("Hi!")

我们先实例化一个String对象并将其赋值给str这个变量,然后我们输出这个str

从str输出的内容来看,str有四个属性,分别是0、1、2、length

//我们一个个输出这些属性
console.log(str[0]) //H
console.log(str[1]) //i
console.log(str[2]) //!
console.log(str['length']) //3

这毋庸置疑,但是接着往下看。

//charAt()是str对象中不存在的属性方法,但是没有报错,依然可以输出!
str.charAt(0) // 输出'H'

charAt()是str对象中不存在的属性方法,但是没有报错,依然可以输出!

这是为什么?这就是进化链__proto__的用处。

str这个对象本身的确没有charAt()这个方法,但是str的进化链上存在这个属性方法,那么charAt()这个方法在进化链的那个节点上呢?

哦~,原来String.prototype拥有charAt这个方法,而str的__proto__指针指向String.prototype

有小伙伴就问了,“那为什么我爷爷写得一手好毛笔字,可我却没遗传这一点呢?”“呵呵”

这么说的话,str.__proto__.__proto__指向的对象所拥有的属性str也都可以直接用喽?答案是肯定的!

看到str.__proto__.__proto__指向的对象所拥有的属性中有一个hasOwnProperty属性方法了么,str可以直接使用这个属性方法。

在验证之前先说下str.__proto__.__proto__指向了谁?指向的是Object的prototype属性。

str.__proto__.__proto__ === Object.prototype // true

Object.prototype.hasOwnProperty()属性方法用来检验一个对象是否自己拥有一个属性而非通过进化链__proto__继承来的属性。

好的,实验开始:

//检查str是否拥有length属性
str.hasOwnProperty('length') //true
//检查str是否拥有0属性(str.charAt(0)的输出是'H')
str.hasOwnProperty(0) //true
//检查str是否拥有1属性
str.hasOwnProperty(1) //true
//检查str是否拥有2属性
str.hasOwnProperty(2) //true
//检查str是否拥有3属性(str的length是3,所以索引值从0开始,所以索引最大是2,所以没有3这个属性)
str.hasOwnProperty(3) //false
//str是否拥有hasOwnProperty这个属性呢?答案是否定的。
str.hasOwnProperty('hasOwnProperty') //false

四、结语

现在再来看这张图,是不是思路清晰多了呢!

当你弄清楚了原型链(我喜欢叫他进化链)__proto__,prototype之间的关系,还有Javascript中12个内置对象,其中10个函数类型,2个对象类型。再来学习这12个内置对象的属性和属性方法是不是如鱼得水,心里跟明镜似的~

对于Javascrip初学者,一时半会肯定还是搞不清楚,唯一的办法就是多看、多想、多模仿、多创新、多总结、多分享~,学习的本质无非就是这些嘛,教育的本质无非就是教会你用学习的本质学习你所感兴趣的嘛。

Javascript中的原型链、prototype、__proto__的关系的更多相关文章

  1. 图解JavaScript中的原型链

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

  2. 深入了解JavaScript中基于原型(prototype)的继承机制

    原型 前言 继承是面向对象编程中相当重要的一个概念,它对帮助代码复用起到了很大的作用. 正文 Brendan Eich在创建JavaScript时,没有选择当时最流行的类继承机制,而是借鉴Self,用 ...

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

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

  4. Javascript中的原型链,__proto__和prototype等问题总结

    1.js中除了原始数据类型 都是对象. 包括函数也是对象,可能类似于C++函数对象把 应该是通过解释器 进行()操作符重载或其他操作, 用的时候把它当函数用就行 但是实际上本质是一个对象 原型也是一个 ...

  5. JavaScript中的原型链原理

    工作中经常解除到prototype的概念,一开始错误的认为prototype是对象的原型链,其实prototype只能算是JavaScript开放出来的原型链接口,真正的原型链概念应该是__proto ...

  6. JavaScript中的原型链和继承

    理解原型链 在 JavaScript 的世界中,函数是一等公民. 上面这句话在很多地方都看到过.用我自己的话来理解就是:函数既当爹又当妈."当爹"是因为我们用函数去处理各种&quo ...

  7. js 原型链 prototype __proto__

    1.说明 函数(Function)才有prototype属性,对象(除Object)拥有__proto__. 2.prototype与__proto__区别 示例: <!DOCTYPE html ...

  8. JavaScript中Function原型及其prototype属性的简单应用

    大家都知道在JavaScript中是没有类的概念的,但是却是有对象的概念的.有的人可能理解对象和类有些迷糊,这里简单的概括一下他们之间的区别: 类:抽象的概念,例如人,动物,汽车等都可以抽象成一个类 ...

  9. JavaScript原型链:prototype与__proto__

    title: 'JavaScript原型链:prototype与__proto__' toc: false date: 2018-09-04 11:16:54 主要看了这一篇,讲解的很清晰,最主要的一 ...

随机推荐

  1. Spring 笔记(一)概念梳理

    概念 预备知识 1. POJO POJO是Plain Old Java Object的缩写,是软件开发大师Martin Fowler提出的一个概念,指的是一个普通Java类.也就说,你随便编写一个Ja ...

  2. python中的re模块,常用函数介绍

    参考: http://www.cnblogs.com/tina-python/p/5508402.htm ======== 1,预定义字符集,可以写在字符集[....]中 \d  数字: \D 非数字 ...

  3. HTML快速入门

    我们经常上网浏览网页,来获取资讯.可网页是什么呢?它又是如何编写出来的呢? 网页又叫Web页面,我们经常可以在网页上看到文字.图片.视频等.我们所要说的HTML(超文本标记语言)就是构成网页文档的主要 ...

  4. 【bzoj4884】[Lydsy2017年5月月赛]太空猫 dp

    原文地址:http://www.cnblogs.com/GXZlegend/p/6825431.html 题目描述 太空猫(SpaceCat)是一款画面精致.玩法有趣的休闲游戏,你需要控制一只坐在迷你 ...

  5. 【Luogu】P2498拯救小云公主(spfa)

    题目链接 我水爆了- - 容易发现可以把两个圆之间连边,左上为起点右下为终点,最小生成树直到起点跟终点连起来,输出边权/2就行. 然后80. 并不理解为什么这可以转化成spfa求最短路,邻接矩阵暴力跑 ...

  6. P4342 [IOI1998]Polygon

    题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘积)标记. 第一步,删除其中一条边 ...

  7. [codeforces] 578C Weakness and Poorness || 三分

    原题 题目定义了两个变量: poorness表示一个区间内和的绝对值. weakness表示一个所有区间最大的poornesss 题目要求你求一个x使得 a1 − x, a2 − x, ..., an ...

  8. UVA 11478(差分约束 + 二分)

    题意: 给定一个有向图,每条边都有一个权值,每次你可以选择一个结点和一个整数的,把所有以v为终点的边的权值减去d, 把所有以v为起点的边的权值加上d 最后要让所有边的权的最小值非负且尽量大 代码 #i ...

  9. CI的model层的操作

    1.需求 整理ci框架下model层的相关操作 2.代码 model的代码,放在application/model目录下,文件名为Coupon.php <?php class Coupon ex ...

  10. 非常好的Linux教程,让你的linux之路更通畅

    1  第1讲.Linux应用与发展(上) 2013-10-22 17:43 | 播放(46) | 评论(0) | 时长:51:38 2  第1讲.Linux应用与发展(下) 2013-10-22 17 ...