【问题标题】:Confusion with "this" object in JavaScript anonymous functions与 JavaScript 匿名函数中的“this”对象混淆
【发布时间】:2009-12-30 17:55:39
【问题描述】:

您好,我正在尝试运行以下 JavaScript 代码。我的目标是掌握this在JavaScript中不同作用域和不同调用类型的含义。

如果您查看下面的代码:我有一个内部匿名函数,它被分配给innerStuff 变量。在该匿名函数中,this 指向 window 对象,而不是外部函数对象或其他任何东西。事件虽然它仍然可以访问 out 函数的变量。

无论如何,我不确定为什么会这样;但是如果你看下面的代码,我稍后会以that 的形式将this 传递给innerStuff,它工作得很好,并在控制台中打印带有doofus 属性的对象。

    var someStuff = {
        doofus:"whatever",
        newF: function()
        {
            var that = this;
            console.log(that);
            var innerStuff = function(topThis){
                console.log(topThis);
            };

            return innerStuff(that);
        }
    }

    someStuff.newF();

现在我只更改一点代码。而不是将它分配给innerStuff,我将直接通过调用它来返回函数,如下所示:

    var someStuff = {
        doofus:"whatever",
        newF: function()
        {
            var that = this;
            console.log(that);
            return function(that){
                console.log(that);
            }();
        }
    }

    someStuff.newF();

这将为内部匿名函数打印 undefined。是因为作为参数传递的that 与在外部函数中定义的that 之间存在冲突吗? 我认为该参数会覆盖可见性。为什么不保留价值?

这完全令人困惑。

另一方面,如果我没有通过that,而是直接使用它,因为可见性在那里,结果是正确的并且符合预期。

我错过了什么?它是否存在于同一范围内的变量之间的冲突? 是否有充分的理由,内部函数将 this 绑定到 window 对象?

【问题讨论】:

    标签: javascript scope this


    【解决方案1】:

    this 在 JavaScript 中指的是您对其调用方法的对象。如果您以someObject.functionName(args) 调用函数,则this 将绑定到该对象。如果你只是调用一个裸函数,如functionName(args),那么this 将绑定到window 对象。

    在第二个示例中的newF 内部,您在内部函数中隐藏了that 变量,但没有向其中传递任何内容,因此它是未定义的。

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

    如果您想要与第一个示例等效的内容(将 that 传递给内部函数),您可能想要以下内容:

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

    或者以下,如果你不想遮蔽它而只使用外部函数的绑定:

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

    【讨论】:

    • 啊!!不敢相信我错过了。非常感谢。
    • 嗯,它与绑定方法在其他所有拥有它们的语言中的工作方式完全不同......
    【解决方案2】:

    在您的第二个示例中,当您调用匿名函数时,未定义参数 that(您没有向其传递任何内容。)您可以这样做:

        newF: function()
        {
            var that = this;
            console.log(that);
            return function(that){
                console.log(that);
            }(that); // note that we are passing our 'that' in as 'that'
        }
    

    这将保持变量的正确值。

    但是,由于您在上面限定var that,您也可以删除函数参数:

        newF: function()
        {
            var that = this;
            console.log(that);
            return function(){
                console.log(that);
            }(); // 'that' is referenced above.
        }
    

    至于为什么匿名函数将window 作为它们的this:每当您调用没有上下文的函数时(即somef()context.somef()this 将指向window 对象。

    您可以覆盖它并在函数上使用.apply(context, argumentsArray) or .call(context, arg1, arg2, arg3) 传递this。一个例子:

        newF: function()
        {
            console.log('Outer:', this);
            var innerF = function(){
                console.log('Inner:', this);
            };
            return innerF.apply(this,arguments);
        }
    

    【讨论】:

      【解决方案3】:

      在您的第一个代码示例中,匿名函数虽然在作为someStuff 对象成员的函数中声明,但不是someStuff 对象的成员。因此,该函数中的this 是对窗口对象的引用。如果您想调用匿名函数并控制 this 引用,您可以执行以下操作:

      var someStuff = {
          doofus:"whatever",
          newF: function()
          {
              var that = this;
              console.log(that);
              var innerStuff = function(){
                  console.log(this);
              };
      
              return innerStuff.apply(this);
          }
      }
      
      someStuff.newF();
      

      在您的第二个示例中,您实际上创建了一个匿名函数,执行它,然后返回匿名函数返回的值。但是,您的匿名函数没有返回任何内容。此外,您还有变量名称冲突。你可以这样做:

      var someStuff = {
          doofus:"whatever",
          newF: function()
          {
              var that = this;
              console.log(that);
              return function(){
                  console.log(that);
                  return true;
              }();
          }
      }
      
      someStuff.newF();
      

      我添加了 return true 是因为你的函数应该返回一些东西,因为正在执行它的函数正在返回匿名函数的返回值。它是返回 true 还是 false 或者是一个字符串还是一个对象或者其他什么取决于场景。

      【讨论】:

      • 我同意第一点,我可以使用“应用”调用,但第二点不正确。没有名称冲突,因为传递的参数确实覆盖了外部函数中的参数。我犯的错误是我在调用时没有将参数传递给匿名函数。 [如上面示例中的 Brian 所示] 他得到了纠正,因为他建议的解决方案工作得很好。至于返回值;我不这么认为,我太在意了;我只是想看看 this/that 的值是如何在内部函数中限定的。不过感谢您的帮助。
      猜你喜欢
      • 2011-09-10
      • 1970-01-01
      • 2012-05-10
      • 1970-01-01
      • 2018-06-11
      • 1970-01-01
      • 2012-03-22
      • 2016-02-25
      • 2013-12-01
      相关资源
      最近更新 更多