JavaScript中this的隐式绑定与调用栈解析

作者:木棉

时间:2026-10-29

浏览:492

本文解析JavaScript中this的隐式绑定机制,指出this指向取决于函数调用时的调用域(call-site)而非声明位置。通过调用栈示例说明函数嵌套调用时this的指向变化,并分析函数引用赋值导致的隐式丢失现象,揭示其最终绑定至全局对象的原理。

文章目录

this隐式绑定与调用域基础

首先通过一个具体示例来展开讨论。


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

在此场景中,this指向了obj对象。原因在于foo函数执行时的调用域(call-site,即调用发生的作用域)位于obj内部。需要特别注意的是,this的指向取决于函数运行时的调用位置,与其在代码中的声明位置无关。

调用域与调用栈的关系

接下来探讨调用域与调用栈的概念。

这里将调用域简称为call-site,调用栈称为call-stack。借助以下代码示例,可以更直观地理解这两个概念之间的关系。


function baz() {
  // call-stack is: `baz`
  // so, our call-site is in the global scope

  console.log( "baz" );
  bar(); // <-- call-site for `bar`
}

当在baz()函数内部调用bar()时,bar的调用域即为baz函数的作用域,此时调用栈中仅包含baz。由于baz函数本身暴露在全局作用域中,因此其自身的调用域也处于全局作用域内。


function bar() {
  // call-stack is: `baz` -> `bar`
  // so, our call-site is in `baz`
  console.log( "bar" );
  foo(); // <-- call-site for `foo`
}
function foo() {
  // call-stack is: `baz` -> `bar` -> `foo`
  // so, our call-site is in `bar`
  console.log( "foo" );
}
baz(); // <-- call-site for `baz`

在理解上述机制后,重新审视开头的示例,逻辑应当更加清晰。本质上,this仅仅指向了其所在的调用域。

函数引用的隐式丢失

此外,还存在另一种常见的操作模式。


function foo() {
  console.log( this.a );
}
var obj2 = {
  a: 42,
  foo: foo
};
var obj1 = {
  a: 2,
  obj2: obj2
};
obj1.obj2.foo(); // 42
Implicitly Lost(隐式丢失)
function foo() {
  console.log( this.a );
}
var obj = {
  a: 2,
  foo: foo
};
var bar = obj.foo; // function reference/alias!
var a = "oops, global"; // `a` also property on global object
bar(); // "oops, global"

尽管bar引用了obj对象上的foo方法,但实际上这等同于直接对foo函数进行引用。因此,在单独调用bar()时,this会按照默认规则绑定到全局对象上。


function foo() {
  console.log( this.a );
}
function doFoo(fn) {
  // `fn` is just another reference to `foo`
  fn(); // <-- call-site!
}
var obj = {
  a: 2,
  foo: foo
};
var a = "oops, global"; // `a` also property on global object
doFoo( obj.foo ); // "oops, global"

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章