【问题标题】:What is lexical 'this'? [duplicate]什么是词汇'this'? [复制]
【发布时间】:2016-04-14 07:05:06
【问题描述】:

谁能给我简单介绍一下这个词法?

“箭头函数表达式(也称为胖箭头函数)与函数表达式相比语法更短,并且在词法上绑定了 this 值(不绑定自己的 this、arguments、super 或 new.target)。箭头函数总是匿名的。”

这是否意味着当我使用“Fat Arrow”函数中的“this”引用调用函数成员时,“this”总是指封闭的“this”?

【问题讨论】:

  • 是的,箭头函数中的this 与创建箭头函数的上下文具有相同的值。
  • 可以说您在该侦听器中有点击侦听器您正在执行一些 ajax 操作,例如 setTimeout。时间完成后,回调中的代码将被执行。在该回调中,您可能已经访问了它更改单击按钮的颜色。但是由于 ajax 操作,控件将脱离该上下文。所以您无法访问 this.so es6 引入了箭头函数来修复 tat 问题
  • This post from @getify 是关于所谓的 lexical this 主题的绝对必读书籍
  • Lexical this 仅仅意味着this 在词法范围内被查找。我想这实际上总是如此。如果我们说箭头函数没有自己的this 值,也许更容易理解。

标签: javascript ecmascript-6


【解决方案1】:

您似乎对箭头函数中this 发生的事情有正确的理解。我将提供一个我认为有助于对话的解释,并希望能巩固您的理解。

您可能知道,当您定义一个函数并在其中使用一个变量时,它会检查该变量是否已在其范围内定义。如果是,它会使用它!如果不是,它会检查该变量定义的封闭范围。它不断检查封闭范围,直到找到变量或到达全局范围。现在,not 箭头函数的函数定义为您隐式定义 this。因此,当您尝试在其作用域中使用 this 时,它们将永远不会检查封闭作用域(因为它们会在自己的作用域中找到它!)。箭头函数不定义自己的this,因此它们会进入封闭范围并查找它,就像它们在您尝试在其范围内使用的任何变量一样。

【讨论】:

  • 这是错误的。变量位于整个作用域链中。 this 是“找到”的,在箭头函数的情况下,正好在 立即 封闭范围内。
  • 我不确定我们是否有不同意见。也许我不清楚。关于你的最后一句话:嵌套箭头函数呢?
  • 谢谢!阅读此答案后,它为我点击了。这让我意识到,在同一范围内,变量和this 是相互独立定义的。
  • 如果你可以从范围中逃脱,它几乎不是一个封闭的范围……为什么 JS 人不谈论线程?它会更加一致。
【解决方案2】:

作为在箭头函数中描述this 行为的一种方式,术语“词法this”介于混淆和错误之间。

行为很简单,箭头函数中的this 指的是周围函数中的this——或者说箭头函数没有定义(或“绑定”)它自己的this

不幸的是,“词汇this”的术语可能因MDN article on arrow functions 中的措辞选择不当而长期存在(直到最近还鼓励人们使用过时的术语“胖箭头函数”)。现在已经清理干净了。另请注意,该规范从未在箭头函数中使用与this 相关的术语“词法”。我很想知道这个表达方式是谁提出来的。

【讨论】:

  • 其实目前的ECMA 2022版本确实调用了“this”这两个可能的值,用于构建函数评估上下文lexical-thisnon-lexical-this,其含义与函数“内部槽”有关" [[ThisMode]],其定义指出:"lexical 表示 this 指的是词法封闭函数的 this 值"。在第 6 版中,这在第 14.2.16 段(简而言之,关于箭头函数的评估:))中简单地说明为“让作用域成为正在运行的执行上下文的 LexicalEnvironment”。确实令人困惑。
【解决方案3】:

假设您有一个点击监听器。在该侦听器中,您正在执行一些 AJAX 操作,例如 setTimeout。达到设定时间后,回调内的代码将被执行。在该回调中,您可能已访问 this 以更改单击按钮的颜色。但是由于 AJAX 操作,控件会脱离上下文。 ES2015 引入了箭头函数来解决这个问题。箭头函数捕获封闭上下文的this 值。

示例用例是:

$('.btn').click(function () {
    setTimeout(function () {
        $(this).text('new'); 
        // This will cause an error since function() defines this as the global object.
    } ,100); 
}); 

为了避免这种情况:

$('.btn').click(function () { // <- Enclosing context
    setTimeout( () => {
        $(this).text('new')  } 
        // This works, because this will be set to a value captured from the enclosing context.
      ,100);
});

【讨论】:

    【解决方案4】:

    wrote an article about this,其要点是:不要考虑“词汇this”的含义。 不要担心箭头函数中的“this”是什么意思。你已经知道(或者至少,如果你不知道,那是你自己对某些外部函数范围的混淆,而不是箭头函数的错)。

    多年来,当您需要在某些嵌套或高阶函数中使用“this”时,您可能已经习惯于担心“this”最终的含义。但是有了箭头功能,你就可以不用担心它了。您几乎可以肯定已经知道“this”在您当前所处的上下文中指的是什么:但是......在箭头函数中,它没有改变。因此,您可以将箭头函数视为简单的情况,而将 function(){} 视为更复杂的情况。

    您是否编写了一些函数并启动一个 if(){} 块并担心“this”可能会在其中更改为什么?不?与箭头函数相同。这就是“词汇this”的意思。它的意思是“Hakuna matata”。

    【讨论】:

    • this 在过去 20 年中的行为是所有 JS 代码的核心,这让我觉得有点奇怪,它是所有 JS 代码的核心,是“复杂的”。它有什么复杂之处?如果这很复杂,那么箭头函数所做的就是通过不定义自己的this 将这种复杂性传递给封闭的函数范围。
    • 你解释它就像箭头函数总是按预期运行,而普通函数永远不会。但是普通函数的 this 行为也很有用,例如在原型中定义方法时。
    • 箭头函数不会改变“this”的当前含义。因此,不需要像“他们在写入时绑定 this 的含义”这样的额外特殊的、令人困惑的解释新的心理模型来理解他们的“this”指的是什么。它所指的内容没有改变。而已。是的,常规功能客观上更复杂。他们还有几个动态属性需要担心。他们已经存在了 20 年,这与这个问题无关。是的,它们仍然有用。但它们不再是完成这项工作的唯一工具。我只是说:尽可能使用更简单的。
    • 重点是,与其让你的大脑加速思考箭头函数对它的意义有一些特殊的新行为,你现在必须坐下来学习,这要容易得多认为他们没有行为。是的,如果您在箭头函数中使用“this”,您可能仍然需要考虑它的含义。但这不是箭头函数的错,也不是它增加了新的复杂性。
    【解决方案5】:

    这是否意味着当我使用“胖箭头”函数中的“this”引用调用函数成员时,“this”总是指封闭的“this”?

    您的问题的答案是。正如您已经说过的那样,胖箭头函数没有this 引用,因此它们使用封闭上下文的引用,这反过来又让我们有机会控制如何在胖箭头函数中调用this回应。

    例如:

    在使用this 的对象内部拥有粗箭头函数将寻找外部上下文。在这种情况下,上下文是window

    var foo = {
      bar: () => this.baz    // 'this' is window      
    }
    

    但是,如果你使用的是公共类字段语法的 ES6 语法:

    class MyClass {
      handleEvent = () => {
        this.letsCode();    // 'this' is instance of MyClass
      }
    }
    

    还有许多其他实例(例如在 HTML 元素上使用 React 的 render 函数来设置点击侦听器)超出了这个问题的范围,其中使用了粗箭头函数并且 this 被适当地绑定到使用它的上下文使我们能够控制其性质。希望对您有所帮助!

    【讨论】:

      【解决方案6】:

      简单来说,我们可以说 lexical this 将引用前一个对象的实例,而 this 则引用当前对象。 如果我们在代码中看到它,它会更有意义。

      var nature = {
      name : "nature",  
      component : ["air","water"],
      printName : function(){
      this.component.forEach(function(){
      console.log(this.name); /* Here this would refer to the object of 
      "component" and not "nature".*/
      });
      }
      }
      nature.printName(); //this would throw an error.
      

      要解决这个问题,lexical this 会有所帮助。让我们看看下面的代码有什么帮助:

       var nature = {
      name : "nature",  
      component : ["air","water"],
      printName : function(){
      this.component.forEach(() => {
      console.log(this.name);  /*Now "this" inside of an arrow 
      function would be a "lexical this" and refer to the object of 
      "nature" and not "component". */
      });
      }
      }
      nature.printName(); //this would print the name.
      

      【讨论】:

        【解决方案7】:

        在 es6 胖箭头函数中使用 this 使得 this 具有词法范围,因为 this 在特定范围内引用的内容被分配给它,这与正常的 es5 函数声明不同,它不断检查 this 引用的内容从最内层作用域到全局作用域,直到找到为止。

        function foo() {
        setTimeout(() => {
            // `this` here is lexically adopted from `foo()`
            console.log( this.a );
        },100);
        }
        var obj = {
          a:2
        };
        foo.call(obj); //2
        

        同时,在 es6 之前,有一种方法可以在 javascript 中实现词法范围,通过将 this 关键字分配给变量,这在一定程度上使 this 成为范围的局部

        function foo() {
        var self = this; // lexical capture of `this`
        setTimeout( function(){
            console.log( self.a );
        }, 100 );
        }
        var obj = {
          a: 2;
        };
        foo.call(obj); //2
        

        【讨论】:

        • this 标识符确实遵循通常的范围链。它的特别之处在于,它在构建执行上下文时在常用函数的本地范围内重新定义,具体取决于函数的类型(对象方法或未绑定函数)和“严格”模式的使用。对于箭头函数,this 没有重新定义,所以它只是在上层范围内解析。请参阅当前规范中的the note(第 6 版也是这样说的,只是用一种更神秘的方式)。
        猜你喜欢
        • 2017-07-09
        • 2011-09-13
        • 1970-01-01
        • 2015-08-10
        • 1970-01-01
        • 2013-08-09
        • 2011-05-10
        • 2014-07-28
        • 2011-05-06
        相关资源
        最近更新 更多