随心记录

Bug不空,誓不成佛

  menu
70 文章
14633 浏览
2 当前访客
ღゝ◡╹)ノ❤️

JS 中原型/原型链 ------ Object 与 Function 的关系理解

原型与原型链

在 JavaScript 中,原型与原型链是一个非常重要的内容,它的作用可以说是一直贯穿整个 JS 编程,关于具体的 原型、原型对象以及原型链概念本编不再做具体解释,前面的学习记录有详细说明,此次只做简单的阐述,本文重点是要谈谈博主对Object 与 Function 的关系之间的分析与理解,如果不对的地方还请指正

原型,原型对象,原型链

  • 首先在 JavaScript 中要明确的几点是:
    • 在 JavaScript 中,万物皆对象,什么都是对象
    • 任何对象都有原型:__proto__
    • 任何方法(包括构造函数,除了 es6 箭头函数,下面讨论均抛开箭头函数先不说)都有原型对象:prototype
    • 顶级原型的原型(__proto__)为 null
    • 任何对象的属性以及方法都在它本身和原型链中进行查找
  • 原型(__proto__):原型就类似于一个指针,指向构造它的构造方法的原型对象
  • 原型对象(prototype):是函数(构造方法)的一个属性,也是一个对象,默认有一个 constructor 属性指回该函数(构造方法)
  • 原型链就是对象的原型一级一级组成的一种抽象的链式结构

注:以下统称原型(__proto__)为 原型(proto), 原型对象为 prototype

JavaScript 中的 Object 与 Function

在 JS 中有两个特殊的实例对象即 ObjectFunction
为什么说这两个特殊呢,因为他们既可以用对象的操作方式,也可以用函数的操作方式,比如 Object.属性 new Object();Function.属性 new Function(),直白点就是 Object 与 Function 既是函数又是方法
一般认为 Object 是 JS 语言中对象的祖先,万物之始,但是用以下代码就会有点疑惑
image.png
从上图可以看出,发现 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__
      image.png
      Object.__proto__.__proto__
      image.png
      Object.__proto__.__proto__.__proto
      image.png
      结论:Object 的原型是一个内置匿名函数(稍后再说),Object 的原型的原型是根源原型对象(稍后说明),因为再网上一层是 null 找到头了。
    • 原型对象(prototype)
      Object.prototype
      image.png
      结论:Object 的原型对象就是根源原型对象
    • 根据以上结果 Object 的原型,原型对象可以有如下图的解释
      image.png
  • Function

    • 原型(proto)以及原型链
      Function.__proto__
      image.png
      Function.__proto__.__proto__
      image.png
      Function.__proto__.__proto__.__proto__
      image.png
      结论:Function 的原型是 内置匿名函数(稍后说明),Function 的原型(内置匿名函数)原型是根源原型对象(稍后说明)
    • 原型对象(prototype)
      Function.prototype
      image.png
      Function.prototype.__proto__
      image.png
      结论:Function 的原型对象是内置匿名函数,Function 的原型对象的原型则是根源原型对象
    • 根据以上结果 Function 的原型对象及原型链可以用如下图表示:
      image.png

有以上结果可以得出:

原型原型对象
Object内置匿名函数根源原型对象
Function内置匿名函数内置匿名函数

image.png
从上述分析可知 Object 的原型与 Function 的原型都是内置匿名函数即有以下结果
Object.__proto__ === Function.__proto__
image.png
因此 Object instanceof FunctionFunction instanceof Object 的结果是相同的。

根源原型对象与内置匿名函数以及顶级实例对象

以下为博主的个人理解与总结
由上述分析结果可得,在 ES5 中,JavaScript 有顶级原型对象以及内置匿名函数,接下来就是实例化的万物祖先 Object 与 Function。
前面也已经说过,所有对象的属性及方法查询的是其所在的原型链且向上查询,即使 Object 也要追寻到根源原型对象查找相关的方法与属性;

  • 根源原型对象:万物继承的开始,即所有原型链的最顶层,所有对象追究原型链最终都会到达的根源
  • 内置匿名函数:JS 特定一个方法对象(或对象方法)用来指派 Function 以及 Object,由此可解释 Object 也可以进行函数或构造方法的操作。内置匿名函数也是一个函数,其按道理来说也有原型对象(prototype),但是因为它是顶头的根源方法,即是对象,也是方法,其原型指向根源原型对象,但是没有原型对象,就像根源原型对象没有原型。
    • 内置匿名函数的内部

      我们已经知道对象的原型指向构造它的构造函数的原型对象,而原型对象里面有默认的 constructor 指向构造函数,上面已经分析出了 Function 的原型,Object 的原型都是内置匿名函数那么既然有原型,说明有构造他们的构造方法,接下来看看内置匿名函数内部有没有构造方法

      image.png

由结果可以得知,构造 Function 与 Object 的构造方法就是 Function它自己本身,这也是 Function 可以与 Object 作为同等级顶级实例的原因。

结论

综上分析完成关系图如下
image.png

注:其他方法指除顶级对象方法外的其他方法和函数(包括内置方法和函数)
其他对象值除顶级对象外的纯对象

根据原型链可以分析,所有的方法都派生于 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 方法
    验证如下:
    image.png
    image.png
    结论:Object 有 a,b 方法

  • Function 的原型链如下:
    Function.__proto__
    image.png

    Function.__proto__.__proto__
    image.png
    结论:Function 也有 a,b 方法

  • 分析 var f = new F()
    f 是通过构造函数 F() 实例化的一个对象,其从原型链查找步骤可如下所示:
    f.__proto__ -> F 的原型对象,此时没有方法 a,b,继续查找
    f.__proto__.__proto__ -> 指向 F的原型对象的原型,即 Object 的原型对象(根源原型对象),因为 F的原型对象的原型也一个对象,当前环境下是由 Object 实例化来的,因此其原型链已经查找到根源原型对象了,从而拥有了 a 方法验证如下:
    image.png

  • 结论:f 拥有 a 方法,没有 b 方法,Object 与 Function 都有 a,b方法

(゚д゚)σ弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌弌⊃