【问题标题】:'this' in arrow function not showing lexical scoping箭头函数中的“this”未显示词法范围
【发布时间】:2020-08-30 02:11:05
【问题描述】:

我试图理解箭头函数中“this”的词法范围。我尝试了以下代码 -

const obj1 = {
  name: "obj1name",
  method: function(){
    return () => {return this.name};
  }
};

const arrowFunc1 = obj1.method();

console.log(arrowFunc1());

const obj2 = {
  name: "obj2name",
  method: function(){
    return obj1.method();
  }
};

const arrowFunc2 = obj2.method();

console.log(arrowFunc2());

这给出了输出 -

obj1name
obj1name

正如预期的那样,箭头函数中的“this”在词法上被限定为 obj1,因此无论我们如何称呼它,它都会打印“obj1name”。到这里为止一切都很好。然后我决定直接将 obj1.method 复制到其中,而不是定义 obj2.method -

const obj1 = {
  name: "obj1name",
  method: function(){
    return () => {return this.name};
  }
};

const arrowFunc1 = obj1.method();

console.log(arrowFunc1());

const obj2 = {
  name: "obj2name",
  method: obj1.method
};

const arrowFunc2 = obj2.method();

console.log(arrowFunc2());

这给出了输出 -

obj1name
obj2name

我不明白为什么它会打印 'obj2name'。

我的理解是,箭头函数是在 obj1.method 中定义的,因此它在其中是词法范围的。因此它应该从 obj1.method 中获取 'this' 的值,即 obj1。

我做错了什么?

【问题讨论】:

  • 箭头函数中的 this 绑定到外部作用域的 this。如果您在对象的方法内定义箭头函数,则外部范围 this 就是您调用该方法时的样子。
  • this 的值绑定到定义箭头函数时的执行上下文。在您的示例中,.method() 的调用定义了this 的内容。 obj1.method() -> obj1, obj2.method() -> obj2 - 只是“正常”this 规则 -> How does the “this” keyword work?
  • @Teemu 但是词法作用域不是静态的(如answer 中所述)?如果作用域取决于函数的调用方式,那不是动态作用域吗?
  • 什么是静态的?在这种情况下,static 表示作用域与其父作用域相同——在第一种情况下,父作用域是 obj1,在第一种情况下是 obj2第二种情况。
  • @muka.gergely 在词法作用域中,作用域是在编译时根据代码的词法结构确定的。正如您所说的那样,父范围在运行时正在发生变化。由于父作用域在运行时发生变化,因此“this”的作用域也在运行时发生变化。那为什么我们称之为词法作用域呢?

标签: javascript this arrow-functions


【解决方案1】:

它是词法范围的:你在 obj1 中定义了一个函数(箭头),但在 obj2 中调用了它 - obj2 的词法范围是 obj2 - 所以你在那里调用的方法按预期工作。

sn-p 中的 console.logs 显示问题:

const obj1 = {
  name: "obj1name",
  method: function(){
    return () => {return this.name};
  }
};

const arrowFunc1 = obj1.method();

console.log(arrowFunc1());

const obj2 = {
  name: "obj2name",
  method: obj1.method
};

const arrowFunc2 = obj2.method();

console.log(arrowFunc2());

// these console.logs show your problem:
console.log('obj1:', obj1)
console.log('obj2:', obj2)

在您的情况下,function()this 创建了范围 - 并且 function()obj2 中。

也许这个 sn-p 有助于理解更多:

// extracted the function, but left the "this"
// just calling the function in itself would throw an
// error, but inside an object (that has a name property)
// it works nicely
const fn = function() {
  return () => {
    return this.name
  }
}

const obj1 = {
  name: "obj1name",
  method: fn
};

const arrowFunc1 = obj1.method();

console.log(arrowFunc1());

const obj2 = {
  name: "obj2name",
  method: fn
};

const arrowFunc2 = obj2.method();

console.log(arrowFunc2());

// these console.logs show your problem:
console.log('obj1:', obj1)
console.log('obj2:', obj2)

还有我的最后一个sn-p:

const obj1 = {
  name: "obj1name",
  method: function() {
    return () => {
      return this.name
    };
  }
};

const arrowFunc1 = obj1.method();

console.log(arrowFunc1());

// if you want to call with obj1, then it's not enough to add the
// function - you have to CALL (invoke) it
const obj2 = {
  name: "obj2name",
  method: obj1.method()
};

// see that there're no parantheses after obj2.method - its
// value is resolved when creating obj2 by INVOKING the function
const arrowFunc2 = obj2.method;

console.log(arrowFunc2());

// these console.logs show your problem:
console.log('obj1:', obj1)
console.log('obj2:', obj2)

【讨论】:

  • 我读了这个answer 来理解词法作用域。据此,词法作用域是静态的,由源代码的结构决定。那么为什么在这种情况下的词法范围取决于我如何调用箭头函数而不是代码结构。那不是动态的吗?
  • @chetanraina 我在我的答案中添加了一个 sn-p:您可以看到函数是在它们包含的对象上调用的,因此范围正在发生变化(只是在它们出现在 JavaScript 时记录了对象本身)
  • @chetanraina 和第三个(最后一个)sn-p:如果您在 obj2 中调用该函数,则它具有 obj1 的范围 - 因为它在那里定义。最初您只是传递了函数,但是通过这种方式传递了 函数的值(在 JS 中,函数是一等公民:ryanchristiani.com/… - 当您传递它们时,这意味着很多)跨度>
【解决方案2】:

这个:

const obj1 = {
  name: "obj1name",
  method: function(){
    return () => {return this.name};
  }
};

应该是这样的:


const obj1 = {
  name: "obj1name",
  method: () => {return this.name}
};

通过将箭头函数包装在常规函数中,作用域再次成为调用者的作用域。

【讨论】:

    猜你喜欢
    • 2016-09-30
    • 1970-01-01
    • 2015-03-17
    • 2018-05-04
    • 1970-01-01
    • 1970-01-01
    • 2018-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多