当我使用 `.call` 方法设置上下文时,为什么嵌套函数中的 `this` 是 window 对象?

问题描述

当我将 this 函数的上下文设置为与对象 window 一起运行时,我不明白为什么 f6 值是 obj 对象。

let obj = {
  color: "blue",name: "maya"
};

function f6() {
  return function() {
    console.log(this);
  }
}

f6.call(obj)();

解决方法

function 函数中,this 不是由词法作用域决定的。 它由函数的调用方式和上下文决定。 每个 function 函数都会创建自己的 this 绑定环境。

function f(){
  this;          // This `this` is distinct …
  
  function g(){
    this;        // … from this `this`.
  }
}
function f(){
  console.log(this);
}

const objX = {
    f
  },objY = {};

objX.f();      // Logs `objX`,because the expression `objX.f` is a member of a reference.
f();           // No `this` binding. `f` by itself isn’t the member of a reference.
f.call(objY);  // Logs `objY`,because `this` was explicitly set.

另一方面,箭头函数从它们的词法作用域获取 this 绑定。 箭头函数不会创建自己的 this 绑定环境。

function f(){
  this;          // This `this` is the same …
  
  () => {
    this;        // … as this `this`.
  };
}

您使用 f6 调用 .call 以提供 this 绑定。 这就是 f6 函数从中获取其 this 值的地方,但 f6 不使用this 值。

与此无关,f6 返回一个碰巧使用 this 的函数。 同样,它是一个 function 函数,因此它的 this 绑定取决于调用。 如果您想知道返回函数的 this 值是什么,您必须检查调用:

f6.call(obj)();

// Equivalent to:
   (f6.call(obj)) ();
// -^^^^^^^^^^^^-      Returned function.
//                ^^   Call.

.call.apply 未用于返回的函数,且未使用 .bind,因此未明确设置 this 绑定。 (f6.call(obj)) 也不是带有引用成员的表达式(即 MemberExpression)。 调用是在没有提供上下文的情况下执行的,因此上下文将是 globalThis 或严格模式下的 undefined

使用箭头函数可以解决这个问题:

function f6(){
  return () => console.log(this);
}

f6.call(obj)(); // Logs `obj`.

或者,在返回中使用 .bind 也可以解决此问题:

function f6(){
  return function(){
    console.log(this);
  }.bind(this);
}

f6.call(obj)(); // Logs `obj`.

当然,使用词法范围1的东西,即变量,也可以解决这个问题:

function f6(){
  const that = this;
  
  return function(){
    console.log(that);
  };
}

f6.call(obj)(); // Logs `obj`.

1:我想你可以说 this 也是词法范围的,但是被每个嵌套的 function 函数所掩盖。


另见: