JavaScript 中 this 指向的原理与内存机制解析

作者:闭包旅人时间:2026-10-22 15:38:04浏览:653

本文深入解析 JavaScript 中 this 关键字的工作原理。从内存中的对象与函数存储结构出发,阐述函数作为独立值在不同上下文执行时的机制。通过字典式属性保存方式,说明 this 如何指代函数当前的运行环境,从而解释 obj.foo() 与 foo() 执行结果差异的根本原因。

问题的由来

一、问题的由来

掌握 JavaScript 语言的一个重要标志,是理解同一段代码在不同写法下可能产生截然不同的执行结果。


var obj = {
 foo: function () {}
};
var foo = obj.foo;
// 写法一
obj.foo()
// 写法二
foo()

在上述代码中,尽管 obj.foo 和 foo 指向的是同一个函数引用,但它们的执行结果却可能不同。具体示例如下。


var obj = {
 foo: function () { console.log(this.bar) },
 bar: 1
};
var foo = obj.foo;
var bar = 2;
obj.foo() // 1
foo() // 2

造成这种差异的核心原因,在于函数体内部使用了 this 关键字。许多教材会解释,this 指向函数运行时所在的环境。对于 obj.foo() 而言,foo 在 obj 对象的环境中运行,因此 this 指向 obj;而对于直接调用 foo() 的情况,foo 在全局环境中运行,因此 this 指向全局对象。这就是两者运行结果不同的原因。

这种解释虽然正确,但往往未深入探讨其背后的机制:函数的运行环境究竟是如何被确定的?例如,为什么 obj.foo() 被视为在 obj 环境中执行,而一旦执行 var foo = obj.foo,foo() 就变成了在全局环境中执行?

本文将深入剖析 JavaScript 这样设计的底层原理。理解这一点,就能彻底掌握 this 的作用机制。

内存的数据结构

二、内存的数据结构

JavaScript 引入 this 的设计,与内存中的数据结构密切相关。


var obj = { foo: 5 };

以上述代码为例,将一个对象赋值给变量 obj。JavaScript 引擎首先在内存中创建一个对象 { foo: 5 },然后将该对象的内存地址赋值给变量 obj。

换句话说,变量 obj 存储的是一个引用地址(reference)。当后续需要读取 obj.foo 时,引擎会先从 obj 获取内存地址,再从该地址读取原始对象,并返回其 foo 属性。

原始对象以字典结构保存,每个属性名都对应一个属性描述对象。以上述例子中的 foo 属性为例,其实际存储形式如下。


{
 foo: {
  [[value]]: 5
  [[writable]]: true
  [[enumerable]]: true
  [[configurable]]: true
 }
}

需要注意的是,foo 属性的具体值保存在属性描述对象的 value 属性中。

函数的存储

三、函数

这种结构非常清晰,但问题在于,属性的值可能是一个函数。


var obj = { foo: function () {} };

此时,引擎会将函数单独保存在内存中,然后将该函数的内存地址赋值给 foo 属性的 value 属性。


{
 foo: {
  [[value]]: 函数的地址
  ...
 }
}

由于函数是一个独立的值,它可以在不同的环境(上下文)中执行。


var f = function () {};
var obj = { f: f };
// 单独执行
f()
// obj 环境执行
obj.f()

环境变量与 this

四、环境变量

JavaScript 允许在函数体内部引用当前环境中的其他变量。


var f = function () {
 console.log(x);
};

在上述代码中,函数体内使用了变量 x。该变量由运行环境提供。

既然函数可以在不同的运行环境中执行,就需要一种机制让函数体内部能够获取当前的运行环境(context)。因此,this 应运而生,其设计目的就是在函数体内部指代函数当前的运行环境。


var f = function () {
 console.log(this.x);
}
上面代码中,函数体里面的this.x就是指当前运行环境的x。
var f = function () {
 console.log(this.x);
}
var x = 1;
var obj = {
 f: f,
 x: 2,
};
// 单独执行
f() // 1
// obj 环境执行
obj.f() // 2

在上述代码中,当函数 f 在全局环境中执行时,this.x 指向全局环境中的 x。

当在 obj 环境中执行时,this.x 指向 obj.x。

回到文章开头提出的问题,obj.foo() 是通过 obj 找到 foo,因此是在 obj 环境中执行。而一旦执行 var foo = obj.foo,变量 foo 直接指向函数本身,因此 foo() 就变成了在全局环境中执行。

总结

以上介绍了 JavaScript 中 this 的工作原理,希望能对大家有所帮助。如有任何疑问,欢迎留言,小编会及时回复。感谢大家对本站的支持!

作者最新文章