欢迎来我的博客阅读:「JavaScript 原型中的哲学思想」

记得当年初试前端的时候,学习JavaScript过程中,原型问题一直让我疑惑许久,那时候捧着那本著名的红皮书,看到有关原型的讲解时,总是心存疑虑。

当在JavaScript世界中走过不少旅程之后,再次萌发起研究这部分知识的欲望,翻阅了不少书籍和资料,才搞懂__proto__prototype的概念。

故以作此笔记,日后忘了可以回来看看。如果你看的过程中觉得理解有些困难,把例子在代码中跑一跑,亲手试一试也许能解决不少疑惑。

一切皆为对象

殊不知,JavaScript的世界中的对象,追根溯源来自于一个 null

「一切皆为对象」,这句着实是一手好营销,易记,易上口,印象深刻。

万物初生时,一个null对象,凭空而生,接着ObjectFunction学着null的模样塑造了自己,并且它们彼此之间喜结连理,提供了prototypeconstructor,一个给子孙提供了基因,一个则制造万千子子孙孙。

在JavaScript中,null也是作为一个对象存在,基于它继承的子子孙孙,当属对象。乍一看,null像是上帝,而ObjectFunction犹如JavaScript世界中的亚当夏娃

原型指针 __proto__

在JavaScript中,每个对象都拥有一个原型对象,而指向该原型对象的内部指针则是__proto__,通过它可以从中继承原型对象的属性,原型是JavaScript中的基因链接,有了这个,才能知道这个对象的祖祖辈辈。从对象中的__proto__可以访问到他所继承的原型对象。

var a = new Array();
a.__proto__ === Array.prototype // true

上面代码中,创建了一个Array的实例a,该实例的原型指向了Array.prototype
Array.prototype本身也是一个对象,也有继承的原型:

a.__proto__.__proto__ === Object.prototype  // true
// 等同于 Array.prototype.__proto__ === Object.prototype

这就说了明了,Array本身也是继承自Object的,那么Object的原型指向的是谁呢?

a.__proto__.__proto__.__proto__ === null  // true
// 等同于 Object.prototype.__proto__ === null

所以说,JavaScript中的对象,追根溯源都是来自一个null对象。佛曰:万物皆空,善哉善哉。

除了使用.__proto__方式访问对象的原型,还可以通过Object.getPrototypeOf方法来获取对象的原型,以及通过Object.setPrototypeOf方法来重写对象的原型。

值得注意的是,按照语言标准,__proto__属性只有浏览器才需要部署,其他环境可以没有这个属性,而且前后的两根下划线,表示它本质是一个内部属性,不应该对使用者暴露。因此,应该尽量少用这个属性,而是用 Object.getPrototypeofObject.setPrototypeOf,进行原型对象的读写操作。这里用__proto__属性来描述对象中的原型,是因为这样来得更加形象,且容易理解。

原型对象 prototype

函数作为JavaScript中的一等公民,它既是函数又是对象,函数的原型指向的是Function.prototype

var Foo = function() {}
Foo.__proto__ === Function.prototype // true

函数实例除了拥有__proto__属性之外,还拥有prototype属性。通过该函数构造的新的实例对象,其原型指针__proto__会指向该函数的prototype属性。

var a = new Foo();
a.__proto__ === Foo.prototype; // true

而函数的prototype属性,本身是一个由Object构造的实例对象。

Foo.prototype.__proto__ === Object.prototype; // true

prototype属性很特殊,它还有一个隐式的constructor,指向了构造函数本身。

Foo.prototype.constructor === Foo; // true
a.constructor === Foo; // true
a.constructor === Foo.prototype.constructor; // true

PS: a.constructor属性并不属于aa.hasOwnProperty("constructor") === false),而是读取的a.__proto__.constructor,所以上图用虚线表示a.constructor,方便理解。

原型链

概念:

原型链作为实现继承的主要方法,其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
每个构造函数都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针(constructor),而实例都包含一个指向原型对象的内部指针(__proto__)。

那么,假如我们让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构造了实例与原型的链条,这就是原型链的基本概念。

意义:“原型链”的作用在于,当读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。以此类推,如果直到最顶层的Object.prototype还是找不到,则返回undefine。

亲子鉴定

在JavaScript中,也存在鉴定亲子之间DNA关系的方法:

  1. instanceof 运算符返回一个布尔值,表示一个对象是否由某个构造函数创建。

  2. Object.isPrototypeOf() 只要某个对象处在原型链上,isProtypeOf都返回true

var Bar = function() {}
var b = new Bar();
b instanceof Bar // true
Bar.prototype.isPrototypeOf(b) // true
Object.prototype.isPrototypeOf(Bar) // true

要注意,实例b的原型是Bar.prototype而不是Bar

一张历史悠久的图

这是一张描述了ObjectFunction以及一个函数实例Foo他们之间原型之间联系。如果理解了上面的概念,这张图是不难读懂。

从上图中,能看到一个有趣的地方。

  1. Function.prototype.__proto__ 指向了 Object.prototype,这说明Function.prototype 是一个 Object实例,那么应当是先有的Object再有Function

  2. 但是Object.prototype.constructor.__proto__ 又指向了 Function.prototype。这样看来,没有FunctionObject也不能创建实例。

这就产生了一种类「先有鸡还是先有蛋」的经典问题,到底是先有的Object还是先有的Function呢?
这么哲学向的问题,留给你思考了。

我只是感慨:越往JavaScript的深处探索,越觉得这一门语言很哲学。

先有鸡还是先有蛋?

update on 2017/01/05

时隔半年,偶尔翻开这篇文章。
对于这个问题,又有了新的思考。
愿意跟能看到这里的你来分享一下。

我们可以先把 Object.prototypeFunction.prototype 这两个拎出来看,因为他们本身就是一个实例对象。
为方便理解,我们改一下名字,避免和 Object 和 Function 的强关联,分别叫:OpFp

那么就有这样的原型链存在了

我再描述一下上面的原型链,先有 null , 再有了 Op , 然后再有了 Fp ,然后以 Fp 为原型的两个构造函数 (Object, Function) 出现了。
而作为构造函数,需要有个 prototype 属性用来作为以该构造函数创造的实例的继承。
所以Object.prototype = Op, Function.prototype = Fp。

JavaScript 原型中的哲学思想相关推荐

  1. JavaScript 原型中的哲学思想 1

    走在求知的路上 2017-02-13 12:45 JavaScript 原型中的哲学思想 JavaScript 原型中的哲学思想 这就产生了一种类「先有鸡还是先有蛋」的经典问题,到底是先有的Objec ...

  2. 物理学中的哲学思想探析

    1.物理学中的唯物辩证法思想 物理学在古代被称为自然哲学,物理学作为一门精密的学科进行研究是从1687年牛顿发表的<自然哲学的数学原理>开始的.随着学科的发展与不断完善,物理学才从哲学中分 ...

  3. linux中的哲学思想

    linux的诞生就注定其成为经典的命运,面对这一经典我们或多或少的要了解一点其中蕴含的哲学思想. 1. 分享(share) 在这个日益注重知识产权的时代,源代码只掌握在少数人手中,只有他们参与研 发和 ...

  4. 软件开发中的哲学思想

    1.面向对象思想对应的哲学思想就是世界是由物质组成的,物质之间是有联系的,物质是运动变化的. 2.MVC设计模式对应的哲学思想就是分而治之,把大问题分解为小问题,把复杂问题分解为简单问题. 3.时间与 ...

  5. JavaScript原型彻底理解2---继承中的原型链

    一.继承的概念 继承是所有的面向对象的语言最重要的特征之一.大部分的oop语言的都支持两种继承:接口继承和实现继承.比如基于类的编程语言Java,对这两种继承都支持.从接口继承抽象方法 (只有方法签名 ...

  6. javascript原型链中 this 的指向

    为了弄清楚Javascript原型链中的this指向问题,我写了个代码来测试: var d = {d: 40};var a = {x: 10,calculate: function (z) {retu ...

  7. javascript原型_在JavaScript中冻结原型时会发生什么

    javascript原型 Have you wondered what happens when you freeze the prototype of an object? Let's find o ...

  8. 深入理解 JavaScript 原型

    前言 原型,作为前端开发者,或多或少都有听说.你可能一直想了解它,但是由于各种原因还没有了解,现在就跟随我来一起探索它吧.本文将由浅入深,一点一点揭开 JavaScript 原型的神秘面纱.(需要了解 ...

  9. Javascript继承机制的设计思想

    我一直很难理解Javascript语言的继承机制. 它没有"子类"和"父类"的概念,也没有"类"(class)和"实例" ...

最新文章

  1. java学习之借书系统
  2. arduinowin7_Arduino在64位WIN7下无法安装驱动的解决办法
  3. 【基础算法复习】01背包问题(一)
  4. 面向对象——单例设计模式
  5. 什么是SLA?SLA管理包括哪些内容?
  6. 树控件单击获取到的节点信息不是当前选中的节点_常用基本控件测试用例(一)...
  7. [深入浅出Cocoa]iOS网络编程之NSStream
  8. squid2.6加速WEB支持虚拟主机配置心得体会 .txt
  9. CortexM0开发 —— LPC11C14的UART使用方法
  10. IIS——屏蔽返回的Header中的 IIS版本信息
  11. 串口ISP方式下载单片机程序设计
  12. java通用教务管理系统_基于java的教务管理系统.doc
  13. 2018科大讯飞营销广告算法大赛
  14. 如何在海量元素中(例如 10 亿无序、不定长、不重复)快速判断一个元素是否存在?
  15. Bluetooth 蓝牙介绍(四):低功耗蓝牙BLE Mesh网络Ⅲ —— 广播 PDU
  16. 雷军周鸿祎黄章,个性及扑朔迷离的关系
  17. 深度学习AI美颜系列---图像自动亮度对比度与调色
  18. java开发中购物车问题,困扰一天的购物车有关问题
  19. 和警察蜀黍拍照像“抓捕现场”?效哥告诉你正确拍照姿势!
  20. 自动化测试 | 解决方案聚焦:如何使用PXI仪器进行高级数字测试

热门文章

  1. 计算机组成微程序设计,微程序设计
  2. linux之父密码,Linux之父十大名言···
  3. HLS—AXI4-Lite Interface
  4. MongoDB分布式操作——分片操作
  5. head,branch,version,date
  6. 分析Oracle有时会用索引来查找数据的原因-oracle执行计划
  7. mybatis多排序问题
  8. Dapper-开源小型ORM
  9. 【Raspberry Pi】webpy+mysql+GPIO 实现手机控制
  10. c++ 或者 vc++中判断程序实例是否运行