一. 无中生有

起初,什么都没有。
造物主说:没有东西本身也是一种东西啊,于是就有了null:

现在我们要造点儿东西出来。但是没有原料怎么办?
有一个声音说:不是有null嘛?
另一个声音说:可是null代表无啊。
造物主说:那就无中生有吧!
于是:

JavaScript中的1号对象产生了,我们把它叫做No. 1。
这个No. 1对象可不得了,它是真正的万物之祖。它拥有的性质和能力,是所有的对象都有的。
__proto__是什么意思呢?那是“生”的意思,或者叫做“继承”。

二. 制造对象的机器

既然有了一个对象,那么剩下就好办了,因为一生二,二生三,三生万物嘛。
但是,造物主很懒,他不想一个一个地亲手制造对象。于是他制造了一台能够造对象的机器:

他给这台机器起了一个名字:Object。
这台机器并不能凭空造出对象,它需要一个模板对象,按照这个模板对象来制造对象。很自然的,它把目前仅有的No. 1对象作为模板。图中的prototype就代表机器的模板对象。

机器又叫做构造函数,为啥呢?因为它是用来构造对象的嘛。

机器如何启动呢?答案是通过new命令。你对着机器喊一声:“new!”,对象就造出来了。

机器的产生,使得生产对象的过程自动化了,解放了造物主的双手,于是造物主忙别的去了。
如果机器只是按照模板的样子,机械地复制出一模一样的对象,那就太笨了。
人类的后代在继承了父辈的性状的基础上,可以产生父辈没有的新的性状。同样地,机器在制造对象时,除了继承模板对象的属性外,还可以添加新的属性。

比如说,有一天Object机器制造一个对象,它有一个特殊的属性,叫做flag,属性值是10。看起来是这样的:

写成代码就是:

var obj = new Object({ flag: 10 });

三. 更多制造对象的机器

一天天过去了,造物主来视察工作,发现Object制造出了很多很多对象。他还注意到:根据“物以类聚”的原则,这些对象可以分成很多类。聪明的造物主想,我何不多造几台机器,让每一台机器负责制造一类对象呢?于是,他造出了几台机器并给它们起了名字,分别是:
String:用来制造表示一段文本的对象。
Number:用来制造表示一个数字的对象。
Boolean:用来制造表示是与非的对象。
Array:用来制造有序队列对象。
Date:用来制造表示一个日期的对象。
Error:用来制造表示一个错误的对象。
多台机器齐开动,各自制造自己负责的那一类对象。轰轰烈烈的造物运动开始了。

造物主又开始思考了,虽然机器是用来制造对象的,但是机器本身实际上也是一种特殊对象啊。现在有了这么多机器,我得好好总结一下它们的共同特征,把它们也纳入对象体系。
于是,造物主基于No. 1对象,造出了一个No. 2对象,这个对象用来表示所有机器的共同特质。换句话说,它是所有机器的原型对象。

(注:__proto__写起来太麻烦了,我们用[p]来代替。)

当然,同Object一样,这些机器也需要各自有一个模板对象,即它们的prototype属性指向的那个对象。显然,它们的模板对象应该是继承在No. 1对象的。即
这张图显示了JavaScript世界中那些最基本的机器本身的继承(__proto__)线路以及它们的模板对象的继承(prototype)线路。只是看起来太复杂了,所以后面我们不再把它们的prototype画出来。

四. 制造机器的机器

造物主想:这下好了,我造出了Object机器,满足了对象制造的自动化。然后又造出了String、Number等机器,实现了特定类别的对象制造的自动化。但是,似乎还缺点什么啊?

对了,还缺少一台制造机器的机器啊!很快,万能的造物主就把它造了出来,并把它命名为Function。有了Function机器后,就可以实现自动化地制造机器了。
首先,Function也是一台机器,所以它的原型对象也是No. 2对象。
其次,Function又是一台制造机器的机器,所以它的模板对象也是No. 2对象。
所以我们得到了Function的一个非常特别的性质:

Function.__proto__ === Function.prototype

哇,太奇妙了!

不要奇怪,这个性质不过是”Function是一台制造机器的机器“这个事实的必然结果。
于是JavaScript的世界的变成了这个样子:从这张图上,我们会发现:所有的函数(包括Function)的__proto__都指向No. 2对象,而同时Function.prototype也是No. 2对象。这说明了:

从逻辑上,我们可以认为所有机器(包括Function自己)都是由Function制造出来的。

同时,如果再仔细瞧瞧,你会发现:

Object作为一个机器可以看做是有由Function制造出来的,而Function作为一个对象可以看做是由Object制造出来的。

这就是JavaScript世界的“鸡生蛋,蛋生鸡”问题。那么到底是谁生了谁呢?Whatever!

五. 让世界动起来

根据上文的叙述,机器用来制造某一类对象。正因为如此,机器可以作为这类对象的标志,即面向对象语言中类(class)的概念。此时,机器被称为构造函数。所以,在ES6引入class关键字之前,我们常常把构造函数叫做类。

然而,除了作为构造函数来制造对象外,函数通常还用作另外的用途:用来做一件事情。正是有了这个功能,JavaScript的世界才由静变动,变得生机勃勃。

比如,我们现在用Function机器制造了鸟类(即用来造鸟的机器):

function Bird(color) { this.color = color; }

然后,对着造鸟机说:“new!”,于是造鸟机发动起来,制造一个红色的鸟:

var redBird = new Bird('#FF0000');

现在我们想让鸟飞起来,于是我们再用Function机器来制造一台机器。这台机器不是用来制造对象的,而是用来做一件事情的,即“让鸟飞起来”这件事情:

// 这是一台通过晃动鸟的翅膀,让鸟飞起来的简陋的机器。 function makeBirdFly(bird) { shakeBirdWing(bird); }

我们知道,让一台制造对象的机器发动,只需要对它喊“new”即可;那么怎样让一台做事情的机器发动呢?更简单,对它咳嗽一声就行了。

makeBirdFly(redBird);

于是红鸟飞起来了,世界充满了生机。

从上面的Bird和makeBirdFly的定义可以看出:实际上,制造对象的机器和做事情的机器没什么明显区别,它们只是使用方式不同。在两种情况下,它们分别被叫做构造函数和普通函数。

说明1:function xxx语法可以看成new Function的等价形式。
说明2:用户自定义的函数通常既可以作为普通函数使用,又可以作为构造函数来制造对象。ES6新增的class语法定义的函数只能作为构造函数,ES6新增的=>语法定义的箭头函数只能作为普通函数。

六. 让世界立体起来

造物主对目前的世界不太满意。因为几乎所有的机器的模板对象都是No. 2,这导致世界看起来有点扁。

于是他又开始研究世界万物的分类问题。它发现有些对象会动、还会吃东西,于是他把它们叫做动物,用机器Animal来制造它们。他进一步发现,即使都是动物,也还是可以进一步分类,比如有些会飞、有些会游,他分别把它们叫做鸟类、鱼类。于是他想,我何不单独造几台机器,专门用来制造某一类动物呢。于是它造出了Bird、Fish等机器。

接下来,在选择这些机器的模板对象时碰到一个问题:如果还像之前那样直接复制一个No. 1对象作为Bird、Fish的模板,那么结果就是这样的:

这样可不好。首先没体现出鸟类、鱼类跟动物的关系,其次它们的模板对象存了重复的东西,这是一种浪费。怎么办呢?很简单,让Bird和Fish的模板对象继承自Animal的模板对象就好了。也就是

Bird.prototype.__proto__ === Animal.prototype Fish.prototype.__proto__ === Animal.prototype

于是:

用同样的方法,造物主造出了一个立体得多的JavaScript世界。

然而还不够。虽然那些纯对象现在充满了层次感,但是那些机器之间的关系还是扁平的:

怎么办呢?其实用类似的办法就行了:

为了做到这点,造物主发明了class关键字。

七. 世界最终的样子

世界现在变得可复杂了,只能画出一部分:

文章出自:JavaScript世界万物诞生记-梦柯教育中国专业的IT职业在线教育平台
交流平台:点击链接加入群【Javaweb前端学习交流】:https://jq.qq.com/?_wv=1027&k=45giNM5

最新文章

  1. linux黄金命令[积累中]
  2. hive 使用where条件报错 java.lang.NoSuchMethodError: org.apache.hadoop.hive.ql.ppd.ExprWalkerInfo.getConvertedNode
  3. Java的线程安全
  4. Machine Learning Algorithms Study Notes(1)--Introduction
  5. ArcGIS API for Silverlight 绘制降雨路径动画
  6. Java基础之读文件——从文件中读取文本(ReadAString)
  7. ZOJ 1610 Count the Colors (线段树 成段更新)
  8. 各种jee服务器的比较,tomcat, jboss, glassfish, websphere, weblogic
  9. 通过设计让APP变快的6个方法
  10. 通知传值 notification
  11. 10种处理PHP字符串的措施
  12. HDU6038-Function-数学+思维-2017多校Team01
  13. 生命周期--JSF
  14. (转)区块链共识机制分析——论PoW,PoS,DPos和DAG的优缺点
  15. PostgreSQL进程和内存结构
  16. 996.icu 事件后
  17. 全国高校绿色计算大赛 预赛第一阶段(C++)第1关:将字符串反转
  18. N! (数组)
  19. 【DB2】监控动态SQL语句
  20. 【Java】认识 JDK,JRE,JVM

热门文章

  1. 关于merge的测试
  2. 20175323《Java程序设计》第四周学习总结
  3. git工作区和暂存区图
  4. Luogu P3802 小魔女帕琪(期望)
  5. xcart-子分类/语言不显示
  6. css---3链接伪类与动态伪类
  7. Widget Factory
  8. Redis相关语法
  9. java char <-> int
  10. Django之深入了解路由层