深入解析JavaScript中Function与Object的关系及原型链机制

作者:异步漫步

时间:2026-10-26

浏览:258

本文深入解析JavaScript中Function与Object的核心关系。通过剖析原型链构建过程,阐明__proto__与prototype的指向逻辑。详细解读instanceof运算符的工作原理及其手写实现,揭示Function与Object互相实例化的特殊现象。同时拆解new关键字的执行步骤,提供手动实现new的完整代码示例,帮助开发者彻底理解JS面向对象机制。

文章目录

原型链

回顾原型概念

  • 在JavaScript中,所有的对象、函数以及数组本质上都被视为对象,这体现了“一切皆对象”的设计哲学。

  • 每个对象内部都持有一个__proto__属性,即隐式原型。该属性指向创建该对象的构造函数的原型对象(Constructor.prototype)。这意味着obj.__proto__===Constructor.prototype,这两个指针实际上指向堆内存中的同一块区域。

  • 在构造函数的原型对象Constructor.prototype中,通常包含constructor属性和__proto__属性。

  • 其中constructor属性存储了函数的相关信息,包括argments、caller、length、name以及指向构造函数原型对象自身的__scope__(即闭包属性,其中存储了函数使用的外部变量及全局上下文,以伪数组形式保存在scope闭包对象中)。至于__proto__,它表示将Constructor.prototype视为通过new操作生成的对象实例,此时__proto__指向的是Constructor.prototype的构造函数(如Superconstructor)的实例对象,即Superconstructor.prototype。

  • 具体结构可参考下图:

  • 原型链

接下来探讨原型链。

  • 由于对象(如obj)的隐式原型(obj.__proto__)指向构造函数的prototype(例如Constructor.prototype)。

  • 而该prototype(如Constructor.prototype)内部又包含一个__proto__,它指向了prototype的构造函数的prototype(例如Superconstructor.prototype)。

  • 随后Superconstructor.prototype.__proto__指向了Object.prototype。

  • 由此形成了一条简单的链式结构,该链条的终点是Object.prototype.__proto__为null。

以上即为原型链的基本构成。

原型链的应用场景。

当访问对象的属性或方法时,引擎会先在当前对象上查找。若未找到,则沿着__proto__查找原型上的属性;若原型中仍无,则继续向上查找原型的原型,直至找到目标属性或到达原型链顶端的null。

关于原型链的一些有趣现象。

我们知道typeof可用于判断变量的数据类型,但对于复杂数据类型,它只能识别出对象、数组或函数,这在实际使用中往往不够精细。

因此,我们可以使用instanceof来判断引用数据类型的对象具体类型。

typeof A //'function'
obj instanceof A //true
obj instanceof Object //true

在实际使用中,我发现一个有趣的问题。

Function instanceof Object //true
Object instanceof Function //true

这是为什么呢?

我们尝试执行以下代码:

Function.__proto__===Object.prototype //false

结果显示为false,这表明Function并非由Object通过new创建。

但是尝试执行:

Object.__proto__===Function.prototype //true

却发现Object是由Function通过new操作生成的。

接着我们分析instanceof的工作原理,尝试用函数instance_of来手写instanceof关键字。

function instance_of(L, R) {
    var O = R.prototype; 
    L = L.__proto__;
    while (true) {    
        if (L === null)      
             return false;   
        if (O === L) 
             return true;   
        L = L.__proto__;  
    }
}

分析上述代码可知,我们实际上是在查找左值的原型链上是否存在右值的原型对象。

于是我们尝试:

Function.__proto__===Function.prototype //true
Function.__proto__.__proto__===Object.prototype //true

发现Function.prototype是由Object通过new生成的,同时Function也可以由自己通过new生成。

  • 综上所述,Function由Function通过new出来生成,Object由Function通过new生成,Function.prototype由Object通过new生成。

最后讨论new关键字。

当代码new Foo(...)执行时,会发生以下过程:

  • 创建一个继承自Foo.prototype的新对象(类似于执行Object.create)。
  • 使用指定的参数调用构造函数Foo,并将this绑定到新创建的对象上。如果new Foo不带括号,则表示没有指定参数列表,此时Foo将不带任何参数进行调用。
  • 由构造函数返回对象,作为new表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1中创建的对象(一般情况下,构造函数不返回值,但可以选择主动返回对象以覆盖正常的对象创建步骤)。

尝试用newFun手写new关键字。

function newFun(Constructor) {
    var obj = {};
    obj.__proto__ = Constructor.prototype;
    return Constructor.apply(obj);    
};

使用Object.create。

function newFun() {
    Constructor = [].shift.call(arguments);// 取出第一个参数Constructor
    var obj = Object.create(Constructor);    
    return Constructor.apply(obj, arguments);// 使用参数调用
};
  • 补充一点题外话。
    let a = {
        k:10,
        hh(){
            console.log(this);
        }
    }
    let b = {
        k:9,
        a
    }
    b.a.hh();
    使用对象链式调用hh()函数,它的this指向通过隐式绑定还是指向直接调用它的对象a,而不是间接调用的对象b

到此这篇关于JavaScript中Function与Object的关系的文章就介绍到这了,更多相关JavaScript Function Object内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章