JavaScript中的此关键字。 完整的*手册

*很可能我错过了一些东西,但是我敢肯定评论会告诉我这一点

我正在写这篇文章是为了满足我的个人需求。 按照计划,它将包含学生就该主题向我提出的所有问题的答案。 如果对其他人有用-很好。

图片

内容内容

  1. 引言
  2. 关于这个的误解
  3. 如何确定这个的价值

引言


this是JavaScript语言最令人困惑的功能之一。 它来自Java,旨在帮助实现OOP。 我用Java编写了一段时间,我必须说,在这段时间里,也许我曾经怀疑在代码的特定位置this等于什么。 在JavaScript中,此类疑问每天都会出现-至少直到您学习一些简单但不明显的规则为止。

关于this误解


关于此关键字,存在几种常见的误解。 我想迅速消除它们,然后再说清楚。

这是一个词汇上下文。

这种印象通常在初学者中产生。 在他们看来, this是一个对象,其中存储了该范围内的所有变量,就像属性一样。 造成这种误解的原因是,在一个特定的情况下,大致来说就是这样。 如果我们处于最高级别,则this等于window (对于浏览器中的常规脚本而言)。 并且我们知道,在顶层声明的所有变量都可以用作window属性。

通常,这是不正确的。 这很容易验证。

 function test(){ const a = "     ,   "; console.log(this.a); } test(); //  ,    

这是该方法所属的对象

同样,在许多特定情况下都是如此,但并非总是如此。 重要的是函数的调用方式,而不是它是否是某个对象的属性。 即使从一个非常简单的逻辑上也可以理解这一点:假设同一函数同时是两个对象的属性。

 const f = function(){ console.log(this); } const object1 = { method: f }; const object2 = { method: f }; 

那么她将成为这些对象中的哪一个?

重要! 即使使用ES6类创建对象,也完全不能保证其方法始终具有this 。 不要被类似于“普通”语言的类所欺骗。

这是一种绝地技巧,一旦学会,就需要在任何地方使用

如果可能的话,最好避免使用this 。 完全合理的唯一情况是OOP。 在其他地方,使用this不仅有害,而且通常会使代码混乱。 从本质上讲, thisthis函数的附加“减去第一”参数,该参数以复杂,不明显的方式传递给初学者。 很有可能将其替换为通常的参数,并且只会变得更好。

如何确定这个的价值


在这里,我将尝试给出一种严格而简洁的算法,即使是没有经验的编码人员也可以使用该算法来理解在特定情况下this等同于什么。 扰流器下方将隐藏更多详细的解释,以免使视觉空间混乱。

  1. 我们在函数内部吗?

    • 是的:请参阅下一项。
    • 否: this等于全局对象

    评注
    在顶级代码中(不在任何函数中), this始终引用全局对象。 对于浏览器中的常规脚本,这是一个window对象。 但总的来说,情况有所不同。
  2. 我们在箭头功能内吗?

    • 是:此值与功能高一级(即包含此功能)相同。 返回上一步并重复执行该算法。 如果该函数未包含在其他函数中,则this是一个全局对象。
    • 否:请参阅下一段。

    评注
    箭头功能的主要特征之一就是所谓的“词汇this ”。 这意味着箭头函数中的this的值仅由创建它的位置(在什么词法上下文中)确定,而不取决于随后调用它的方式。 有时这不是我们需要的,但更多时候它使箭头功能变得非常方便和可预测。
  3. 此函数是否称为构造函数(使用new运算符)?

    • 是: this是指“正在建设中”的新对象。
    • 否:请参阅下一段。

    评注
    也许值得分别指定继承的ES6类的构造方法的情况。 然后,在调用super()之前,它没有值(访问它会导致错误),并且在调用super()它等于父类的新对象。
  4. 该函数是使用bind创建的吗?

    • 是:此值等于创建此函数时传递给bind方法的第一个参数的值。
    • 否:请参阅下一段。

    评注
    bind方法创建该函数的副本,并对其进行修复,还可以修复this函数的前几个参数。 实际上,这不仅创建了函数的副本,而且还引用了“异国BoundFunction对象”。 它的异国情调特别体现在,通过反复调用bind我们再也不能改变this 。 因此,严格来说,本段中的答案应表述为:如果是,则this等于第一次调用 bind一个参数,从而导致创建此函数。
  5. 此函数是否作为回调或处理程序传递到某处?

    • 是的:只有主知道召唤时这等于什么。 请去阅读会导致问题的文档。
    • 否:请参阅下一段。

    评注
    对于非箭头绑定函数,其值取决于调用它的环境。 如果您不是亲自调用它,而是将它传递到某个地方,则this值可能会或可能不会被未知值替代。

    范例:

     `use strict` document.addEventListener('keydown', function(){ console.log(this); }); //    this === document.    DOM- this  currentTarget [1, 2, 3].forEach(function(){ console.log(this); }); //         ,  undefined. ?     . 
  6. 使用applycall调用此函数。

    • 是:在这种情况下, this等于传递给相应方法的第一个参数。
    • 否:请参阅下一段。

    评注
    显式设置this方法的另一种方法。 更确切地说,两个。 但是, this applycall之间没有区别,唯一的区别是其余参数的传递方式。
  7. 是否将此函数作为对象属性的值获取并立即调用?

    • 是: this等于上述目的。
    • 否:请参阅下一段。

    评注
    实际上,通过这种机制(以及使用其他语言的经验),人们开始相信“ this是我们调用其方法的对象”。 也许我只写代码。

     'use strict'; const object1 = { method: function(){ console.log(this); } } const object2 = { method: object1.method } object1.method(); //    object1 -           object1['method'](); //  .        object2.method(); //    object2 -  " ",      ,         
  8. 代码是否在严格模式下执行? (“使用严格”,ES6模块)

    • 是: this等于undefined
    • 否: this等于全局对象。

    评注
    如果到了这一点,那么任何可以设置它的机制this不会设置它。 关于如何将其传递还有各种误解。 例如,在面试中他们经常告诉我这样的事情:

     const obj = { test: function(){ (function(){ console.log(this); })(); //      } } obj.test(); //  ,     obj.   

    或者,正如我在“误解”部分中所述,许多人认为,如果函数是使用ES6类创建的对象的方法,则该函数将始终等于其中的该对象。 这也不是真的。

    因此,如果到了这一点,那么调用函数的其他情况就无关紧要了。 而这一切都取决于我们是否处于严格模式。

    历史上,作为“默认” this ,将全局对象传递给此类函数。 这种方法后来被认为是不安全的。 ES5引入了一种严格的模式,可以解决早期版本的ECMAScript的许多问题。 它包含在文件或函数开头的“ use strict”指令中。 在此模式下,此参数的“默认”值是undefined

    在ES6模块中,默认情况下启用严格模式。

    还有其他包括严格模式的机制,例如,在NodeJS中,可以使用--use-strict标志为所有文件启用严格模式。


通常,仅此而已。 当然,它的定义比我们希望的要简单,但也没有看起来那么困难。 将这个算法作为乘法表来学习-您再也不会遇到问题了。 这样的事情。

PS用户Aingis建议在使用with构造时,作为上下文传递到其中的对象将替换全局对象。 也许我不会将其输入到我的分类器中,因为在2019+年相遇的机会很小。 但是无论如何,这是一个有趣的观点。

PPS用户rqrqrqrq建议new优先级高于bind优先级。 分类器已进行相应的修订。 谢谢你

Source: https://habr.com/ru/post/zh-CN464163/


All Articles