【问题标题】:Function context ("this") in nested functions嵌套函数中的函数上下文(“this”)
【发布时间】:2013-02-03 21:42:14
【问题描述】:

当您在 Javascript 中调用顶级函数时,函数内的 this 关键字指的是默认对象(如果在浏览器中,则为窗口)。我的理解是,将函数作为方法调用是一种特殊情况,因为默认情况下它是在窗口上调用的(如 John Resig 的《JavaScript Ninja 的秘密》第 49 页中所述)。事实上,以下代码中的两个调用都是相同的。

function func() {
  return this;
}

// invoke as a top-level function
console.log(func() === window); // true

// invoke as a method of window
console.log(window.func() === window); // true

到目前为止一切都很好......现在这是我不明白的部分:

当一个函数嵌套在另一个函数中并且在没有指定要调用的对象的情况下被调用时,函数内部的 this 关键字也指的是 window。但是不能在窗口上调用内部函数(参见下面的代码)。

function outerFunc() {
  function innerFunc() {
    return this;
  }

  // invoke without window.* - OK
  console.log(innerFunc() === window); // true

  // invoke on window
  //window.innerFunc(); - error (window has no such method)
  console.log(window.innerFunc) // undefined
}

outerFunc();

嵌套函数在窗口上不可用是完全有道理的,因为它毕竟是嵌套的......但是我不明白为什么 this 关键字指的是窗口,就好像该函数是在窗口上调用的一样.我在这里错过了什么?

编辑

以下是对以下优秀答案和我的一些后续研究的总结。

  • 说“正常”调用函数与将其作为窗口的方法调用是一样的,这是不正确的。仅当函数被全局定义时,这才是正确的。

  • 函数上下文(this 关键字的值)不取决于函数的定义位置/方式,而是取决于调用它的方式。

    李>
  • 假设代码未在严格模式下运行,“正常”调用函数会将函数上下文设置为窗口(在浏览器中运行时,或在其他环境中运行相应的全局对象)。

  • 上述规则的一个例外是使用 bind 创建函数。在这种情况下,即使“正常”调用该函数,它也可能具有 window 之外的上下文。也就是说,在这种情况下,上下文取决于您如何创建函数,而不是如何调用它。虽然严格来说这并不准确,因为 bind 创建了一个新函数,该函数在内部使用 apply 调用给定函数。该新函数的上下文仍将由其调用方式确定,但它通过使用 apply 屏蔽了其内部调用的函数的上下文。

通过“正常”调用,我指的是以下简单的调用方式:

myFunction();

为了完成图片,这里简要介绍其他调用方式和相应的上下文:

  • 作为对象(方法)的属性——上下文就是对象

  • 使用 apply 或 call - 明确指定上下文

  • 使用 new 运算符(作为构造函数) - 上下文是一个新创建的对象

如有需要,请随时更新以上内容,以帮助有类似问题的人。谢谢!

【问题讨论】:

标签: javascript


【解决方案1】:

您可以使用functionName() 调用范围内的任何函数。由于您没有在对象上调用它,它将在默认对象 (window) 的上下文中调用。 (IIRC,如果您处于严格模式,它将在 undefined 的上下文中调用)。

上下文的默认对象与函数的定义位置或函数出现的范围无关。它只是默认对象。

如果函数是对象的属性,则可以将其调用为reference.to.object.function(),它将在object的上下文中调用,而不是默认对象。

其他改变上下文的东西是new 关键字和applycallbind 方法。

【讨论】:

    【解决方案2】:

    在 JavaScript 中,当在没有显式上下文的情况下调用函数时,上下文就是全局对象。对于网络浏览器,全局对象是window

    此外,JavaScript 具有函数作用域,因此函数内的任何变量或函数都不能在该函数之外的作用域内访问。这就是你无法访问window.innerFunc的原因。

    【讨论】:

      【解决方案3】:

      一个函数是否嵌套在另一个函数中与调用该函数时this的值无关。唯一重要的是:

      • 如果通过遍历对象的属性“找到”函数,则this 的值将是对该对象的引用:

        someObject.prop( whatever );
        

        函数的声明方式无关紧要。

      • 如果您使用call()apply() 调用函数,则this 的值取自您使用的函数的第一个参数。

      • 如果您使用bind() 为函数创建了绑定包装器,则this 的值将与调用bind() 时请求的值相同。

      • 如果您使用new 作为构造函数调用函数,则this 将引用新创建的对象实例。

      • 否则,this 要么是对全局上下文的引用,要么是 undefined(在“严格”模式下或在符合 ES5 的运行时中)。

      当然,定义函数的代码中的“位置”很重要,因为范围包括它包含的任何符号,并且无论如何获得对它的引用,这些符号都可用于函数。

      【讨论】:

        【解决方案4】:

        它不依赖于函数在哪里声明,而取决于它是如何被调用的:

        var obj = {
           f: function() {
               return this;
           }
        }
        
        var f = obj.f;
        
        console.log(obj.f()) // obj
        console.log(f()) // window/default obj
        

        或者换句话说。语法obj.f() 使用this=obj 执行函数,而f() 使用this=window 执行函数。在 JavaScript 中,调用者指定 this 的值。

        【讨论】:

          【解决方案5】:

          当您在全局范围内定义func 时,它实际上被分配为window 对象的属性。也就是说,window 对象包含所有全局范围的变量。 (*) 因此,funcwindow.func 代表相同的东西。 innerFunc 在函数范围内定义,在该范围之外不可用。因此,window.innerFunc(仍然)是undefined

          但是,this 上下文取决于您调用函数的方式。当您调用像obj.method() 这样的方法时,this 上下文设置为obj。另一方面,您也可以自己调用该方法:

          var f = obj.func;
          f(); // in this call: this === window
          

          在这种情况下,您没有在对象上调用函数,因此this 上下文设置为默认值。然而,默认值是 全局范围,如上所述,这由 window 表示。

          您始终可以使用Function.prototype.call()Function.prototype.apply() 覆盖this 上下文,它们将this 上下文作为第一个参数。例如:

          var f = obj.func;
          f.call(obj); // in this call: this == obj
          

          (*) 请注意,这只适用于在浏览器中运行的 JavaScript。在其他环境中,这可能会有所不同。例如,在 Node.js 中,GLOBAL 变量包含全局范围。

          【讨论】:

            猜你喜欢
            • 2021-08-07
            • 2018-03-15
            • 2012-03-27
            • 2014-01-10
            • 2013-09-08
            • 2020-09-18
            • 1970-01-01
            • 2015-11-18
            • 1970-01-01
            相关资源
            最近更新 更多