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

本贴最后更新于 1886 天前,其中的信息可能已经物是人非

原型与原型链

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

原型,原型对象,原型链

  • 首先在 JavaScript 中要明确的几点是:
    • 在 JavaScript 中,万物皆对象,什么都是对象
    • 任何对象都有原型:__proto__
    • 任何方法(包括构造函数)都有原型对象: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 方法

  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    729 引用 • 1327 回帖
  • 经验
    25 引用 • 157 回帖
  • 积累
    5 引用 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...