6

当您在 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 关键字指的是窗口,就好像函数是在窗口上调用的一样。我在这里想念什么?

编辑

以下是以下优秀答案的摘要以及我的一些后续研究。

  • 说“正常”调用函数与将其作为window的方法调用是一样的,这是不正确的。只有在全局定义函数时,这才是正确的。

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

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

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

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

myFunction();

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

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

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

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

如有必要,请随时更新上述内容,以使有类似问题的人受益。谢谢!

4

5 回答 5

1

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

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

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

其他改变上下文的东西是new关键字和apply, call, 和bind方法。

于 2013-02-03T21:46:02.530 回答
1

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

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

于 2013-02-03T21:46:50.693 回答
0

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

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

    someObject.prop( whatever );
    

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

  • 如果您使用call()apply()调用一个函数,那么 的值this将从您使用的任何一个函数的第一个参数中获取。

  • 如果您已经为函数创建了一个绑定包装器bind(),那么 的值this将在bind()被调用时根据请求而定。

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

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

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

于 2013-02-03T21:48:45.450 回答
0

它不依赖于函数的声明位置,而是它的调用方式:

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.

于 2013-02-03T21:49:09.063 回答
0

当您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.

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

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

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

于 2013-02-03T21:54:06.520 回答