原型与原型链
在 JavaScript 中,原型与原型链是一个非常重要的内容,它的作用可以说是一直贯穿整个 JS 编程,关于具体的 原型、原型对象以及原型链概念本编不再做具体解释,前面的学习记录有详细说明,此次只做简单的阐述,本文重点是要谈谈博主对Object 与 Function 的关系之间的分析与理解,如果不对的地方还请指正
原型,原型对象,原型链
- 首先在 JavaScript 中要明确的几点是:
- 在 JavaScript 中,万物皆对象,什么都是对象
- 任何对象都有原型:
__proto__
- 任何方法(包括构造函数,除了 es6 箭头函数,下面讨论均抛开箭头函数先不说)都有原型对象:
prototype
- 顶级原型的原型(
__proto__
)为 null - 任何对象的属性以及方法都在它本身和原型链中进行查找
- 原型(
__proto__
):原型就类似于一个指针,指向构造它的构造方法的原型对象 - 原型对象(prototype):是函数(构造方法)的一个属性,也是一个对象,默认有一个 constructor 属性指回该函数(构造方法)
- 原型链就是对象的原型一级一级组成的一种抽象的链式结构
注:以下统称原型(
__proto__
)为 原型(proto), 原型对象为 prototype
JavaScript 中的 Object 与 Function
在 JS 中有两个特殊的实例对象即 Object 与 Function。
为什么说这两个特殊呢,因为他们既可以用对象的操作方式,也可以用函数的操作方式,比如 Object.属性 new Object();Function.属性 new Function()
,直白点就是 Object 与 Function 既是函数又是方法 。
一般认为 Object 是 JS 语言中对象的祖先,万物之始,但是用以下代码就会有点疑惑
从上图可以看出,发现 Function 竟然与 Object 相互等价,第一个代码结果为 true 还好理解毕竟万物皆对象 Function 也是 Object 对象的一种,但是第二个代码的结果为 true 就有些耐人寻味了,Object 竟然也是 Function 的一种??
其实这俩的存在地位相当于兄弟,只不过 Object 的权利更大些,接下来就进行两者的具体分析。
分析 Object 与 Function
从上图的 instanceof 结果来看,要想分析产生的原因还得看 instanceof 本身是如何去判断的,有如下实例 x instanceof y,该操作的返回结果取决于 y 的 原型(proto) 是否在 x 的原型链之上,如果在则返回 true 否则返回 false。
通过上述结果就可以得知 Object 的原型与 Function 的原型互相在其原型链之上。因此接下来对 Object 的原型及其原型对象和 Function 的原型及其原型对象进行分析。
-
Object
- 原型(proto)以及原型链
Object.__proto__
Object.__proto__.__proto__
Object.__proto__.__proto__.__proto
结论:Object 的原型是一个内置匿名函数(稍后再说),Object 的原型的原型是根源原型对象(稍后说明),因为再网上一层是 null 找到头了。 - 原型对象(prototype)
Object.prototype
结论:Object 的原型对象就是根源原型对象 - 根据以上结果 Object 的原型,原型对象可以有如下图的解释
- 原型(proto)以及原型链
-
Function
- 原型(proto)以及原型链
Function.__proto__
Function.__proto__.__proto__
Function.__proto__.__proto__.__proto__
结论:Function 的原型是 内置匿名函数(稍后说明),Function 的原型(内置匿名函数)原型是根源原型对象(稍后说明) - 原型对象(prototype)
Function.prototype
Function.prototype.__proto__
结论:Function 的原型对象是内置匿名函数,Function 的原型对象的原型则是根源原型对象 - 根据以上结果 Function 的原型对象及原型链可以用如下图表示:
- 原型(proto)以及原型链
有以上结果可以得出:
原型 | 原型对象 | |
---|---|---|
Object | 内置匿名函数 | 根源原型对象 |
Function | 内置匿名函数 | 内置匿名函数 |
从上述分析可知 Object 的原型与 Function 的原型都是内置匿名函数即有以下结果
Object.__proto__ === Function.__proto__
因此 Object instanceof Function
与 Function instanceof Object
的结果是相同的。
根源原型对象与内置匿名函数以及顶级实例对象
以下为博主的个人理解与总结
由上述分析结果可得,在 ES5 中,JavaScript 有顶级原型对象以及内置匿名函数,接下来就是实例化的万物祖先 Object 与 Function。
前面也已经说过,所有对象的属性及方法查询的是其所在的原型链且向上查询,即使 Object 也要追寻到根源原型对象查找相关的方法与属性;
- 根源原型对象:万物继承的开始,即所有原型链的最顶层,所有对象追究原型链最终都会到达的根源
- 内置匿名函数:JS 特定一个方法对象(或对象方法)用来指派 Function 以及 Object,由此可解释 Object 也可以进行函数或构造方法的操作。内置匿名函数也是一个函数,其按道理来说也有原型对象(prototype),但是因为它是顶头的根源方法,即是对象,也是方法,其原型指向根源原型对象,但是没有原型对象,就像根源原型对象没有原型。
-
内置匿名函数的内部
我们已经知道对象的原型指向构造它的构造函数的原型对象,而原型对象里面有默认的 constructor 指向构造函数,上面已经分析出了 Function 的原型,Object 的原型都是内置匿名函数那么既然有原型,说明有构造他们的构造方法,接下来看看内置匿名函数内部有没有构造方法
-
由结果可以得知,构造 Function 与 Object 的构造方法就是 Function它自己本身,这也是 Function 可以与 Object 作为同等级顶级实例的原因。
结论
综上分析完成关系图如下
注:其他方法指除顶级对象方法外的其他方法和函数(包括内置方法和函数)
其他对象值除顶级对象外的纯对象
根据原型链可以分析,所有的方法都派生于 Function(类似于继承),但其又属于对象,所以也派生于 Object,而所有普通对象派生于 Object。
要说谁是老大呢,看样子 Function 是与 Object 同级的,但因为 Object 又是万物始祖,即管后面的函数又管后面的对象,所以 Object 总的来说控制能力还是比 Function大。
Object 与 Function 的不解之缘分析完毕,下面诸如此类的原型及原型链的问题就迎刃而解,有如下题:
var F = function () {}
Object.prototype.a = function () {
console.log('a 方法')
}
Function.prototype.b = function () {
console.log('b 方法')
}
var f = new F();
/* 问:f 有无方法 a,b,Function,Object 有无方法 a,b 吗?*/
分析:首先看一个对象有无某个属性或方法先从他自己本身去找,没有的话去寻找它的原型链,如果搜寻到了根源原型对象即原型链的顶层还没有则会返回 undefined 或 not a function。
从代码上看明显的 f,Function,Object 没有直接的定义 a,b 方法,而 Object 与 Function 的原型对象定义了 a,b 方法,此时可以先看 Object 与 Function 的原型链上找,是否可以找到 a,b。
-
本篇已经得出结论 Function 的原型对象是内置匿名函数而 Object 的原型对象是根源原型对象而内置匿名函数的原型(proto)则指向根源原型对象,此时内置匿名函数拥有 b方法,根源原型对象拥有 a 方法。Object 的原型链上
Object.__proto__ ->内置匿名函数,拥有 b 方法
Object.__proto__.__proto__ ->根源原型对象,拥有 a 方法
。
验证如下:
结论:Object 有 a,b 方法 -
Function 的原型链如下:
Function.__proto__
Function.__proto__.__proto__
结论:Function 也有 a,b 方法 -
分析
var f = new F()
f 是通过构造函数 F() 实例化的一个对象,其从原型链查找步骤可如下所示:
f.__proto__ -> F 的原型对象
,此时没有方法 a,b,继续查找
f.__proto__.__proto__ -> 指向 F的原型对象的原型,即 Object 的原型对象(根源原型对象),因为 F的原型对象的原型也一个对象,当前环境下是由 Object 实例化来的,因此其原型链已经查找到根源原型对象了,从而拥有了 a 方法
验证如下:
-
结论:f 拥有 a 方法,没有 b 方法,Object 与 Function 都有 a,b方法