玩转 JavaScript 之不得不懂的原型

概述

本系列文章的第一篇中提到了对象类型,对象是 JavaScript 中的重要角色之一,本篇便从原型这个知识点切入,但愿你们在阅读过本篇文章以后脑海中都可以创建起一张完整的思惟导图。浏览器

函数与对象的关系

首先咱们要肯定一点,函数是一种可调用的对象,也在本系列第一篇中曾提到过,咱们能够作以下校验:bash

(()=>{}) instanceof Object   // true
复制代码

其次咱们要肯定,对象都是经过函数建立的,好比咱们平时写的对象字面量,其实只是 new Object() 之类的语法糖而已。函数

知道以上两点以后,咱们能够说,函数是一种对象,对象又是经过函数建立,因此对象建立对象。是否会以为有点不明觉厉的感受?其实要弄清楚它们之间的关系,不用去管这些弯弯绕。post

只要再明白一点,JavaScript 中除了 Object ,还存在一个角色,那就是 Function学习

咱们先来看一下在浏览器控制台打印出 ObjectFunction 的结果:spa

>  Object
<· ƒ Object() { [native code] }
>  Function
<· ƒ Function() { [native code] }
复制代码

原型

原型属于 JavaScript 的核心,咱们一步步来分析,了解原型的方方面面。prototype

prototype[[Prototype]]

咱们知道函数是可调用对象,既然是对象,函数也是属性的集合。这些属性中其中一个就是 prototype 属性,也就是咱们一般所说的原型。全部函数都有 prototype 属性 (Function.prototype.bind() 例外)。而 prototype 是一个对象,它有个 constructor 属性指向这个函数。这里用思惟导图表示出来,你们能够自行在浏览器窗口打印相关信息来印证。code

从上图能够很清楚看出 function Foo()Foo.prototype 的关系,同时咱们会看到实例对象 foo 有一个 __proto__ 属性指向 Foo.prototype__proto__咱们称为隐式原型,只是对象内置属性[[Prototype]]的非标准实现,虽然浏览器都支持可是不推荐使用。cdn

下文为方便表达理解,[[Prototype]] 内置属性会用 __proto__ 表示。对象

ES6中推荐使用 Object.getPrototypeOf()方法来返回一个对象的 [[Prototype]],使用 Object.setPrototypeOf() 方法来设置一个对象的 [[Prototype]]

更进一步

咱们知道 Foo.prototype 也是一个对象,那它的 __proto__ 指向哪里呢?

咱们知道 function Object() 也是函数,因此它和普通构造函数拥有一样的规则,不一样点在于,Object.prototype 位于原型链顶端,看图:

由上图可知,Foo.prototype__proto__指向了 Object.prototypeObject.prototype 也是一个对象,它的 __proto__ 指向了 null,这应该好理解,意思就是到顶了。

解开谜团

是时候解开谜团了,上文也提到 function Function() 也是函数,是否是和 function Foo()function Object()适用一样的规则呢?答案是确定的,看下图:

这里除了上面的规则,咱们还应注意到几个点:

  • function Foo()function Object()__proto__属性都指向了 Function.prototype,这说明函数都是经过 Function构造函数 new 出来的
  • function Function() 是个例外,虽然它的 __proto__ 也指向了Function.prototype,可是是引擎先内建了 Function.prototype, 而后才有 function Function(),因此并非本身建立本身;
  • Function.prototype__proto__ 指向了 Object.prototype,是由于引擎先建立 Object.prototype,再建立 Function.prototype,并将二者用 __proto__ 联系起来。

原型链

上面的图已经画出了一条条的箭头指向的链条,经过 __proto__ 属性链接,这就是原型链。

具体的能够理解为:当寻找一个对象的某个属性时,若是没有找到,则会顺着 __proto__ 属性指向的原型对象上查找,一直往上直到 Object.prototype,这一条查找的线路就被称之为原型链。

总结

为方便理解,总结必不可少:

  1. Object.prototypeFunction.prototype 是两个特殊对象,由引擎建立,因此不用纠结这俩对象怎么来的了;
  2. 对象都能经过 __proto__ 属性找到 Object.prototypeObject.create(null) 创造出的对象例外,由于没有 __proto__ 属性;
  3. 函数都能经过 __proto__ 属性找到 Function.prototype;
  4. 对象都是函数 new 出来的,除了上面两个特殊对象;
  5. 函数的 prototype 是对象,它有个 constructor 属性指向构造函数自己;
  6. 对象的 __proto__ 指向原型, __proto__ 将对象和原型链接起来组成了原型链。

你或许会问,直到这些有什么用呢?那就涉及到类和继承方面的问题了,下篇再见!

玩转 JavaScript 系列

写做是一个学习的过程,尝试写这个系列也主要是为了巩固 JavaScript 基础,并尝试理解其中的一些知识点,以便能灵活运用。本篇同步发布在「端技」公众号,若是有错误或者不严谨的地方,请务必给予指正,十分感谢!

整个系列会持续更新,不会完结。

全目录

1. 玩转 JavaScript 之 数据类型

2. 玩转 JavaScript 之不得不懂的原型

相关文章
相关标签/搜索