本系列文章的第一篇中提到了对象类型,对象是 JavaScript 中的重要角色之一,本篇便从原型这个知识点切入,但愿你们在阅读过本篇文章以后脑海中都可以创建起一张完整的思惟导图。浏览器
首先咱们要肯定一点,函数是一种可调用的对象,也在本系列第一篇中曾提到过,咱们能够作以下校验:bash
(()=>{}) instanceof Object // true
复制代码
其次咱们要肯定,对象都是经过函数建立的,好比咱们平时写的对象字面量,其实只是 new Object()
之类的语法糖而已。函数
知道以上两点以后,咱们能够说,函数是一种对象,对象又是经过函数建立,因此对象建立对象。是否会以为有点不明觉厉的感受?其实要弄清楚它们之间的关系,不用去管这些弯弯绕。post
只要再明白一点,JavaScript 中除了 Object
,还存在一个角色,那就是 Function
。学习
咱们先来看一下在浏览器控制台打印出 Object
和 Function
的结果: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.prototype
, Object.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
,这一条查找的线路就被称之为原型链。
为方便理解,总结必不可少:
Object.prototype
和 Function.prototype
是两个特殊对象,由引擎建立,因此不用纠结这俩对象怎么来的了;__proto__
属性找到 Object.prototype
,Object.create(null)
创造出的对象例外,由于没有 __proto__
属性;__proto__
属性找到 Function.prototype
;new
出来的,除了上面两个特殊对象;prototype
是对象,它有个 constructor
属性指向构造函数自己;__proto__
指向原型, __proto__
将对象和原型链接起来组成了原型链。你或许会问,直到这些有什么用呢?那就涉及到类和继承方面的问题了,下篇再见!
写做是一个学习的过程,尝试写这个系列也主要是为了巩固 JavaScript 基础,并尝试理解其中的一些知识点,以便能灵活运用。本篇同步发布在「端技」公众号,若是有错误或者不严谨的地方,请务必给予指正,十分感谢!
整个系列会持续更新,不会完结。