【问题标题】:javascript this of the outer function of closure having a bound 'this'javascript this的闭包外部函数有一个绑定'this'
【发布时间】:2017-06-15 18:40:05
【问题描述】:

我很难理解这个问题。 我知道范围链、javascript 中的回调、回调中 this 的值以及箭头函数。

在 javascript 中,闭包可以通过作用域链访问封闭函数的变量。那么为什么闭包不访问通过 Function.prototype.bind 绑定到闭包的父函数的“this”呢?变量“this”不是作用域链的一部分吗?

在 chrome 控制台中运行以下代码:

a = 4;
b = 6;
function outer(){
    function inner(){
        console.log(`this.a is ${this.a} and this.b is ${this.b}`);
    }
    inner();
}
outer.bind({a:1,b:3})()

控制台又退回来了:

this.a is 4 and this.b is 6

【问题讨论】:

  • 那是因为你有全局变量! this 里面的 inner 仍然是 window 访问全局变量。
  • @AndrewLi 好的,我明白了,内部不应该访问外部的边界 a 和 b,因为它是一个闭包?
  • 不,因为您在闭包中访问this。与外部函数无关。
  • 所以你的意思是说'this'与范围链无关?
  • @AndrewLi ,好吧,你的意思是说,当我定义这个函数时,这是在函数范围内通过引擎内部分配的?

标签: javascript ecmascript-6 ecmascript-5


【解决方案1】:

这和闭包是 JS 中的两种不同机制,不应混用。 外部函数中的 this 与内部函数中的 this 完全分离。

在您的示例中,您期望内部函数从外部函数具有 this 的词法范围,但这不是 this 的工作方式。如果您使用箭头函数,它的工作方式就是这样,因为这将是词法的,并且会从外部函数指向 this。 如果将内部函数更改为箭头函数,则可以观察到该行为 // this.a 为 1 而 this.b 为 3

const 内部 = () => { 控制台.log(this.a is ${this.a} and this.b is ${this.b}); };

如果你想了解这是如何表现的,我强烈推荐 Kyle Simpson 的书,它在 github this & object prototypes 上免费提供

从书中。

要理解这个绑定,我们必须理解调用点:代码中调用函数的位置(而不是声明函数的位置)。我们必须检查调用站点来回答这个问题:this 指的是什么?

所以你可以看到内部函数的位置与 this 绑定的内容无关。 rules that defines how this will be bound

阅读以上链接后,您应该对 JS 中的这一点有更多的了解。

【讨论】:

    【解决方案2】:

    变量“this”不是作用域链的一部分吗?

    是的,没错。 this 不是变量,而是特殊关键字。它确实在每个函数调用中设置,在您的情况下为inner()。在outer 范围内的this 是什么并不重要。

    但是有一个例外,函数可以选择退出这种行为:箭头函数。他们确实在词汇上查找this,并忽略了调用中的值:

    function outer(){
        const inner = () => {
            console.log(`this.a is ${this.a} and this.b is ${this.b}`);
        }
        inner();
    }
    outer.call({a:1,b:3})
    

    【讨论】:

    • 所以解释器首先在内部检查函数调用是“方法”还是“普通函数调用”,在前一种情况下,this 是方法附加到的 obj,并且在后者是全局对象,即使函数是一个闭包并且没有附加到全局对象[当然,在非严格模式下]。 ? ?
    • 是的,这就是它检查的内容。请注意,它没有将全局对象传递给inner(),而是传递给undefined——它没有像你所说的那样附加到任何东西上。只有草率的模式函数才会将未定义的 this 参数转换为全局对象,就像箭头函数或绑定函数选择忽略该值一样。 (总是尝试严格模式:D!)
    【解决方案3】:

    正如 cmets 中所述,这是一个 contextual reference,它可以根据您调用函数的方式(或定义它,如果我们考虑箭头函数)而改变。查看显示此上下文行为的代码的修改版本:

    var a = 4;
    var b = 6;
    function outer(){
        document.write(`<p>[outer] this.a is ${this.a} and this.b is ${this.b}</p>`);
    
        function inner(msg){
          document.write(`<p>[${msg}] this.a is ${this.a} and this.b is ${this.b}</p>`);
        }
        inner('inner');
        this.inner = inner;
        this.inner('this.inner');
    }
    outer.bind({a:1,b:3})();
    

    它会输出:

    [outer] this.a is 1 and this.b is 3
    
    [inner] this.a is 4 and this.b is 6
    
    [this.inner] this.a is 1 and this.b is 3
    

    工作演示here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-25
      • 2017-06-18
      • 2016-12-22
      • 1970-01-01
      • 1970-01-01
      • 2015-08-10
      相关资源
      最近更新 更多