在这种情况下,我与箭头功能中的“ this”关键字混淆

时间:2020-05-21 18:11:05

标签: javascript ecmascript-6 closures arrow-functions

我有两种情况,我对我得到的输出感到困惑。

案例1:

let x = {
  b: 5,
  y: function a() {
    return function() {
      return () => {
        console.log(this);
      }
    }
  }
}
x.y()()();

在运行x.y()()()时,我得到Window对象作为输出,但是根据箭头函数的定义,输出应该是其父函数。

案例2:

let x = {
  b: 5,
  y: function a() {
    return () => {
      console.log(this);
    }
  }
}
x.y()();

如果我删除一个嵌套级别(这是一个基本示例),然后在运行x.y()()时,我将得到对象x作为输出。

您能否解释为什么我确切地得到这些输出?

4 个答案:

答案 0 :(得分:2)

第一个函数调用是

x.y()

在该函数调用中,this将引用x。该函数调用返回一个函数,该函数将在第二个函数调用中使用:

x.y()()

函数调用没有显式的this值,因此thiswindow。该函数调用返回另一个函数,即最里面的箭头函数,该函数根据其定义从其闭包中继承window作为this。因此,第三个函数调用:

x.y()()()

还将window作为this的值。

答案 1 :(得分:2)

函数内部的this由其调用上下文以及该函数是否为箭头函数确定。

使用箭头功能,this始终从外部范围继承。

如果要调用的函数是完整的function ,并且该函数作为对象的属性(例如obj.foo())被调用,则调用上下文this函数中的fooobj

如果要调用的函数是完整的function但是独立的-即不是对象的属性-则没有调用上下文,并且this函数内部将是undefined或全局对象。

使用

let x = {
  b: 5,
  y: function a() {
    return function() {
      return () => {
        console.log(this === window);
      }
    }
  }
}
x.y()()();

this是返回的函数this的含义-即,此处调用的函数的调用上下文:

x.y()()

被调用的函数不是对象的一部分-它是一个独立的函数表达式,是通过在对象上调用 prior 函数创建的,等效于:

(x.y())()

因此,没有调用上下文,this是全局对象。

相反,在情况2中,被调用的最接近的祖先function是对象的a属性上的y函数,而该函数通过调用上下文进行调用:

x.y()()
^^^^^

上面,y是通过x的调用上下文来调用的,因此thisx函数内的a

答案 2 :(得分:0)

您的问题类似于以下问题:-Javascript "this" pointer within nested function

在父对象内部调用函数 -对于x.y(),它有一个前导父x,这就是为什么它返回x -在x.y()()和x.y()()()的情况下,将调用内部函数,该函数没有前导父对象,因此将返回window。

答案 3 :(得分:0)

这是怎么回事...

首先,让我们稍微修改一下代码-但在进行此操作之前,让我们先讨论什至会影响this :“ CallSite”。

CallSite

在其中调用函数的位置将确定其this的值,并且在此确定旁边还有一个先例顺序。基本上,有四种类型的CallSite,但是,有1或2个警告,可以说是5或6种。

CallSite的4种类型

  • 全球
  • 隐含
  • 明确
全球

这是相当明显和直接的...调用与任何对象分离的函数,this将成为 Global Scope

function run() {
  this === window === true;
}
隐含的

也相当简单。调用任何函数作为对象的方法,this将等于该对象的实例。

function run() { return this; }
run();  // Global
({ id: 'test', run: run }).run();  // > { id: 'test', run: f() }
明确的(请参见下面的警告)

直接。使用Function.prototype.callFunction.prototype.apply调用函数将 force this等于原型方法的第一个参数。但是,此规则有一个警告-请继续关注。

(function run() { return this; }).call(new Klass());  // this instanceof Klass === true

尽可能简单。调用一个函数,并在调用之前加上newthis会等于隐含类的新实例。但是,这确实有一个例外。

CallSite优先级的注意事项

明确的

Function.prototype.callFunction.prototype.apply 如果函数是调用Function.prototype.bind 的结果,则不能强制函数的上下文。此外,值得一提的是,在已绑定的函数上调用不会重新绑定到另一个上下文;它的Function.prototype.bind值将与原始this调用的值保持不变

bind

在调用带有function run() { return this; } let o = { }; let x = { }; let r = run.bind(o); let result = r.call(x); // result === x === false && result === o === true 前缀的函数时,如果该函数返回不同的值,则不会获得隐含类的对象实例。

new

您的代码(已修改)

在原始代码中,您会返回class Class {} var Klass = function Klass() { return new Class; }; var klass = new Klass(); // klass instanceof Class === true 的值,因为箭头功能总是将最外面的作用域放到自己的作用域中。也就是说,箭头功能将始终采用其父级范围的x上下文。此行为返回返回在函数上调用this并提供Function.prototype.bind作为其上下文的结果

this

当我们调用var x = { b: 5, y: function a() { console.log('a', this); return function b() { console.log('b', this); // window } return () => { console.log('=>', this); // x } } } x.y()(); 时,我们将返回该函数返回的任何内容。我已经修改了您的代码以提供两种返回方案:

  • 返回x.y()function b() {...}是一个分离的功能。因此,其CallSite将为 Global
  • 返回x.y()() => {...}是一个分离的箭头功能。它的行为就像您在规范函数上调用x.y()并在[parent]函数的bind上下文中作为第一个参数传递一样。

关闭

我希望这在进一步了解CallSite之后变得更加有意义。知道了这一点,您就会意识到实际上可以使用this作为调用策略。也就是说,尝试找出以下代码如何成功运行:

练习1(“克罗福德犬球问题”)

以下两行代码表现出什么行为?

new

练习2(“新功能”)

编写一个函数,该函数可以补救以下代码以成功运行。

var a = new (function Klass() {})();  // a
var b = new (function Klass() {}());  // b

希望这会有所帮助!