JavaScript中Object和Function及其prototype之间的关系

引子

在nodejs中执行如下代码

> Object instanceof Function
true

> Function.prototype instanceof Object
true

> Function instanceof Function
true

是不是有点迷惑?

instanceof的真实含义

在js中判断某个实例是否某个类的实例,我们可以是用如下代码:

function Test() {}
var t = new Test();
t instanceof Test;  // true

从字面上看,要表达的意思很直接。然而让我们hack一下代码,看看会发生什么:

var testPrototype = Test.prototype;
Test.prototype = {};
t instanceof Test;  // false

当Test类的原型更新为另一个对象时,之前用Test创建的实例其原型不变,依旧是Test上原先的prototype。从这个例子可以看出,我们可以大致这么理解instanceof这个语法:

t inheritsFrom Test.prototype

为了获得或判断t的真实原型,ES5提供了Object.getPrototypeOf()和Object.prototype.isPrototypeOf()方法:

Object.getPrototypeOf(t) === testPrototype;  // true
testPrototype.isPrototypeOf(t);  // true

构造函数只是实例和原型的连接器

当使用构造函数创建对象后,对象与其原型已经联系起来,之后构造函数对于这两者已经没有什么存在的意义了。我们用猎头撮合人才与公司签订劳动协议来举例子:

          劳动协议签订完毕
人才 --------------------------> 公司

       猎头:没我什么事儿了……

这个法则也适用于js对象的原型继承:

            继承关系建立
实例 --------------------------> 原型

       构造函数:没我什么事儿了……

构造函数就像中介,用来联系实例和原型。构造函数和原型虽然有prototype属性联系,但他们真的没什么大关系。

整理混乱的关系

在js中不污染prototype时具有以下规则:

  • 所有function都继承自Function.prototype
  • Object构造函数也是function,因此也继承自Function.prototype
  • Function构造函数也是function,因此也继承自Function.prototype
  • Function.prototype继承自Object.prototype,但增加了callable的支持,即可以在标识符后边使用()来触发调用

继承关系图

Object.prototype
        ^
        |
Function.prototype
    ^        ^
    |        |
 Object   Function

验证代码:

> Object.getPrototypeOf(Object.prototype) === null
true

> Object.getPrototypeOf(Function.prototype) === Object.prototype
true

> Object.getPrototypeOf(Object) === Function.prototype
true

> Object.getPrototypeOf(Function) === Function.prototype
true
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容