为什么原型链是这样的

50 阅读2分钟

其实学习前端到现在对于原型链的知识掌握的一直都不是很熟练,这次尝试记录一下我的一些思考。


主要想能够理解以下问题

  1. 为什么Object.proto===Function.prototype
  2. 为什么Function.proto===Function.prototype
  3. 为什么Function.prototype.proto===Object.prototype

一个简单的记忆方法

  • 对于第一点我们知道Object其实也是一个函数,所以他的原型是Function.prototype
  • 对于第二点目前来看似乎只能记住Function.proto===Function.prototype
  • 对于第三点我们知道Function.prototype是一个对象,所以Function.prototype的原型应该是Object.prototype

思考一下为什么这么设计

我们知道,JS是通过原型链的方式模拟面向对象。需要通过原型链的方式能够追溯一个对象的血缘关系。 一个对象持有proto属性用于访问[[prototype]],而一个函数则持有prototype属性记录对应的原型对象。 这种思考方式在JS中函数作为一等公民的视点来看,隐约察觉到一点先有鸡还是先有蛋的问题。

比如我们在上述的简单记忆方式中一会将Object作为对象看待,一会改变视角将Object当作函数看待。而对于Function我们也是同样的处理逻辑。这种处理方式让我初次接触真的难以理解这到底是怎么交织在一起的。

后续我的理解中改变视角不再从原型链从下往上追溯而是先默认这几个第一性原理。

  • Object.prototype为对象原型
  • Function.prototype为函数原型
  • 每个对象都有proto指向其原型

对于第一点: Object是一个函数,因此Object必须继承函数的特性,所以Object.proto必须指向一个包含这些函数方法的原型,此时系统中只有 Function.prototype 包含这些函数方法,所以:Object.proto === Function.prototype


对于第二点:Function是一个对象,所以Function 必须能访问对象的基本方法。所以Function的原型链必须包含 Object.prototype,但 Function 同时也是函数,所以Function的 proto 又得指向 Function.prototype,所以需要Function.prototype.proto===Object.prototype,保证依据当前链条查找既能找到对象基本方法,也能保持函数的特征


对于第三点: 必须让 Function.prototype.proto 指向 Object.prototype。这样,通过 Function → Function.prototype → Object.prototype的链条,Function既能访问函数方法,也能访问对象方法。


为什么不是Function.proto===Object.prototype

           prototype
Function--------------->Funticon.prototype
           \     / proto           |
             \ /                   |
             / \                   | proto       
            /   \                  |
          /       \ proto          |
Object----------------->Object.prototype----->null
           prototype

Function 是创建函数的函数,它必须具有函数的基本能力(call、apply等)。如果直接从 Object.prototype继承,就会失去这些函数特性。


为什么不让对象原型和函数原型统一起来


会导致一个普通的对象也可以被当作函数一样执行,而一个函数上也会挂载一些不需要的属性