为什么嵌套的局部函数将`this`绑定到窗口而不是父窗口

Nad*_*oli 5 javascript scope this

我正在阅读一些关于javascript的文档,并偶然发现了以下代码示例:

var o = {
  value: 1,
  outer: function () {
    var inner = function () {
      console.log(this);  //bound to global object
    };
    inner();
  }
};
o.outer();
Run Code Online (Sandbox Code Playgroud)

它输出window.

我想不通,为什么this(绑定到全局对象的关键字window),而不是父对象(outer).
如果outer要从inner范围访问,则必须将outers this(就像传递outer自身一样)inner作为参数传递给其本地函数.所以,正如所料:

var o = {
  value: 1,
  outer: function () {
    var inner = function (that) {
      console.log(that);  //bound to global object
    };
    inner(this);
  }
};
o.outer();
Run Code Online (Sandbox Code Playgroud)

输出outer.

是不是有点在一个废话outer的范围this被绑定到对象本身(即outer),而在inner的范围,这是局部的outer,this被重新绑定到全局对象(即它覆盖outer的捆绑)?


所述的ECMAScript规格规定,输入功能代码的执行上下文时,如果«提供thisArg呼叫者»要么是未定义,然后this被绑定到全局对象.

但是以下内容:

var o = {
    outer: function () {
        var inner = function () {
            console.log('caller is ' + arguments.callee.caller);
        };
        inner();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出对象outer本身:

caller is function () {
    var inner = function () {
        console.log('caller is ' + arguments.callee.caller);
    };
    inner();
}
Run Code Online (Sandbox Code Playgroud)



另一方面,但可能是相关的,请注意:
严格模式下,第一个代码段输出undefined而不是窗口.

Roc*_*mat 6

这是因为this运行函数时设置,而不是在定义函数时设置.

例如:

var o = {
    func: function(){
        console.log(this);
    }
};
Run Code Online (Sandbox Code Playgroud)

当你打电话时o.func(),你是在上下文中这样做的o,所以它按预期工作.

现在让我们说你这样做:

var f = o.func;
f();
Run Code Online (Sandbox Code Playgroud)

这不会按预期工作.这是因为,当你调用f(),它没有任何上下文连接到它,所以thiswindow.

您可以通过使用.call更改值来解决此问题this.

var f = o.func;
f.call(o);  // sets `this` to `o` when calling it
Run Code Online (Sandbox Code Playgroud)


Aln*_*tak 3

这就是语言的工作原理。

每次调用函数时,this都会被重置。在嵌套(内部)函数中,它不会像其他(显式声明的)变量那样从封闭范围继承值。

默认情况下 this将设置为window除非该函数被调用为:

  • myObj.func(arg1, ...)或者
  • func.call(myObj, arg1, ...)或者
  • func.apply(myObj, [arg1, ...])

在这种情况下this将等于myObj

以任何其他方式调用的函数,即使它最初被定义为对象的属性(var func = myObj.func; func()即将使用window.

还有一个名为 的实用函数.bind,它以这样的方式包装函数引用,您可以提供一个始终用作的特定值this

var myFunc = myObj.func;                // obtain reference to func
var bound = myFunc.bind(someOtherObj);  // bind it to "someOtherObj"

bound();                               // this === someOtherObj
bound.call(myObj)                      // this still === someOtherObj
Run Code Online (Sandbox Code Playgroud)