JavaScript 的“this”关键字解释和揭秘
JavaScript 的“this”关键字解释和揭秘

这 这个 关键字是一把双刃剑——它可能是复杂错误的来源——一旦你知道它是如何工作的,它也可以让你作为开发人员的生活更轻松。这些天来,我觉得社区将语言推向了更多功能范式。我们没有使用 这个 关键字这么多。而且我敢打赌,它仍然会使人们感到困惑,因为它的含义因上下文而异。所以,在这篇文章中, 这个 将解释关键字,以便您更好地了解它的实际工作原理。
介绍
本文适用于所有 Javascript 开发人员。您将学习以下内容:
- 什么
这个关键字在 Javascript 中? - 什么
这个关键字在节点中表示。 - 如何
这个关键字在全局和函数执行上下文中确定。 - 调用函数的不同方式及其关联方式
这个 - 如何控制值
这个使用称呼()和申请()方法。 - 如何使用
绑定()方法。 - 如何
这个表现在箭头函数中
是什么 这个 关键词
这 这个 关键字是在 Javascript 中调用函数时用于存储对象引用的变量。对象 这个 关键字引用或指向取决于上下文 这个 用于。从概念上讲, 这个 类似于英语中的代词,因为它用于指代对象——就像代词指代名词一样。
例如:“玛丽跑得很快,因为 她 正试图赶上公共汽车。”
在上面的陈述中,代词“she”用于指代先行词(先行词是代词所指的名词)“玛丽”。让我们将这个概念与 这个 关键词。
const person = { 姓名:“玛丽”,
代词:“她”,
Activity: function () { // this = person console.log(`${person.name} 跑得很快,因为 ${this.pronoun} 正试图赶上公共汽车`) } } person.Activity() // Mary 跑得很快,因为她想赶公共汽车
在前面的代码中 这个 被用作的参考值 人 对象,就像代词“she”用来指代“Mary”一样。
价值如何 这个 决定
这 这个 关键字由 执行上下文 简而言之,执行上下文是 Javascript 用于代码执行的抽象环境,它有三种变体:
- 全局执行上下文
- 函数执行上下文
还有 评估() 执行上下文,但由于其恶意性质而很少使用。读这个 文章 了解有关执行上下文的更多信息。
全局执行上下文
在全局执行上下文中, 这个 关键字引用全局对象,即 窗户 Web 浏览器上的对象。
console.log(window === this) // true this.color = 'Green' console.log(window.color) // 绿色
在前面的代码中,将一个属性添加到全局 窗户 对象通过 这个 关键词。
注意: 在全局执行上下文中 这个 无论 Javascript 是处于严格模式还是非严格模式,关键字都将始终引用全局对象。
这个 节点中的关键字
按照 NodeJS 文档
在浏览器中,顶级作用域是全局作用域。这意味着在浏览器中,如果您在全局范围 var 中,某些东西将定义一个全局变量。在 Node.js 中这是不同的。顶级范围不是全局范围; var Node.js 模块中的某些内容将是该模块的本地内容。
上述声明的意思是 这个 关键字不引用 NodeJS 中的全局对象。相反,它指向当前使用它的模块——即通过它导出的对象 模块.exports .
例如,让我们看一个名为 应用程序.js
┣ app.js
控制台.log(this);
module.exports.color = '绿色';
控制台.log(this);
输出:
┣ $ 节点 app.js
{}
{颜色:'绿色'}

在前面的代码中,首先记录了一个空对象,因为其中没有值 模块.exports 在里面 应用程序.js 模块。然后 颜色 属性被添加到 模块.exports 对象,当 这个 再次记录更新的 模块.exports 对象返回一个 颜色 财产。
Node如何访问全局对象
我们现在知道, 这个 关键字不像在浏览器中那样引用 Node 中的全局对象。在 Node 中,全局对象是使用 全球的 关键字,无论在哪里 全球的 使用关键字。
┣ app.js console.log(global);
输出:
┣ $ node app.js // 记录节点全局对象

全局对象公开了有关 Node 环境的各种有用属性。
函数执行上下文
在函数执行上下文中如何 这个 关键字的确定取决于调用函数的方式。
可以通过四种方式调用 Javascript 函数:
- 作为函数调用
- 作为方法的调用
- 作为构造函数调用
- 使用 apply 和 call 方法调用
当一个函数被作为函数调用时(即当一个函数被使用 () 操作员), 这个 引用全局 窗户 对象在 非严格的 模式并设置为 不明确的 在 严格的 模式。
例子
function A() { console.log(this === window) // true }
function B() { "use strict" console.log(this === window) // false } function C() { "use strict" console.log(this === undefined) // true}
一个(); // 真的
乙(); // 错误的
C(); // 真的
当函数作为方法调用时(即通过对象属性), 这个 引用该方法的“拥有”对象。
例子
让尼日利亚= {大陆:'非洲',getContinent:函数(){返回this.continent; } }
console.log(Nigeria.getContinent()); // 非洲
要将函数作为构造函数调用,我们在函数调用之前加上 新的 操作员。
例子
函数上下文(){返回这个; }
新上下文();
当函数作为构造函数调用时(通过 新的 操作员)发生了一些特殊的动作:
- 创建了一个新的空对象
- 该对象作为
这个参考对象——即对象这个将指向函数何时被调用。 - 新构造的对象作为
新的运营商的价值。
例子
函数 Person() { this.name = 'Mary', this.age = 20 }
const person1 = new Person();
console.log(person1.age) // 20

前面的代码和图表显示并解释了如何 这个 当函数作为构造函数调用时,将引用一个对象。
如果您尝试在没有 新的 操作员, 这个 将指向 不明确的 ,而不是一个对象。
例子
function Person() { this.name = 'Mary', this.age = 20 } const person2 = Person(); console.log(person2.age) // // => TypeError: Cannot read property 'age' of undefined
为了确保 人() 函数总是使用构造函数调用来调用的,你在开头添加一个检查 人() 功能:
function Person() { if (!(this instanceof Person)) { throw Error('必须使用 new 运算符调用函数'); }
this.name = '玛丽',
这个.age = 20 }
const person2 = Person(); console.log(person2.age) // // => 必须使用 new 运算符调用函数
ES6 引入了一个元属性,名为 新目标 这允许您检测函数是作为简单调用还是作为构造函数调用的。
您可以修改 人() 函数使用 新目标 元属性:
函数人(){
if (!new.target) { throw Error('必须使用 new 运算符调用函数'); }
this.name = '玛丽', this.age = 20 }
const person2 = Person();
控制台日志(person2.age)
// // => 必须使用new操作符来调用函数
函数是对象,和所有 Javascript 对象一样,它们也有方法。其中两种方法, 称呼() 和 申请() ,间接调用函数。这两种方法都允许您明确指定 这个 value(object reference) 用于调用,这意味着您可以调用任何函数作为任何对象的方法,即使它实际上不是该对象的方法。 称呼() 和 申请() 还允许您指定调用的参数。这 称呼() 方法使用自己的参数列表作为函数的参数,并且 申请() 方法期望将一组值用作参数。同时 称呼() 和 申请() 第一个论点是 这个 关键字——表示要在其上调用函数的对象。
例子
function getContinent(prefix) { console.log(`${prefix} ${this.continent}`); } 让尼日利亚= {大陆:'非洲'}; 让中国= {大陆:'亚洲'}; getContinent.call(nigeria, "尼日利亚在"); getContinent.call(china, "中国在");
输出:
尼日利亚在非洲 中国在亚洲
在这个例子中,我们称 获取大陆() 间接使用函数 称呼() 的方法 获取大陆() 功能。我们通过了 尼日利亚 和 中国 对象作为第一个参数 称呼() 方法,因此,我们在每次调用中都得到了对应国家的大陆。
这 申请() 方法类似于 称呼() 方法,但正如您已经知道的那样 - 它的第二个参数是一个参数数组。
getContinent.apply(nigeria, ["尼日利亚在"]); getContinent.apply(china, ["中国在"]);
输出:
尼日利亚在非洲 中国在亚洲
在箭头函数中,JavaScript 设置 这个 词汇上 .这意味着 这个 箭头函数内部由最接近的包含“非箭头”函数定义。此外,价值 这个 箭头函数内部无法更改。它在函数的整个生命周期中保持不变。
让我们看一些例子:
让 getThis = () => 这个; console.log(getThis() === 窗口); // 真的
在这个例子中, 这个 值设置为全局对象,即网络浏览器中的窗口对象。让我们借助 堆 和 堆 .

- 这
得到这个箭头函数的词法范围是全球的()返回全局的“非箭头”函数窗户目的。 - 这
这个中的价值得到这个箭头函数是全局的窗户对象自这个函数的值在词法范围内指向这个对象。
让我们看另一个例子:
function confirmThis () { let getThis = () => this; console.log(getThis() === 窗口); // true } confirmThis();
输出:
由于 这个 “正常”函数的值指向全局 窗户 对象处于“非严格模式”。这 这个 值也将指向 窗户 对象,因为它的词法范围是 确认这个() 功能。但是,在“严格”模式下,情况就不同了。
function confirmThis () { "use strict" let getThis = () => this; console.log(getThis() === 窗口); // true } confirmThis();
输出:
这 这个 的价值 确认这个() 功能将是 不明确的 在严格模式下,同样适用于 得到这个 箭头函数。
该方法创建了一个新函数,在调用该函数时,该函数具有
_这个_关键字设置为提供的值,在调用新函数时在任何提供的参数之前具有给定的参数序列。
例子
常量模块 = { x: 42, getX: function() { return this.x; } };
常量 unboundGetX = module.getX; console.log(unboundGetX());
// 函数在全局范围内被调用
// 预期输出:未定义 const boundGetX = unboundGetX.bind(module); console.log(boundGetX()); // 预期输出:42
在前面的代码中 模块 对象方法 获取X() 被调用为“函数”(而不是 模块 ) 在全局范围内。这会导致它失去它 这个 参考 模块 目的。为了 这个 仍然指向 模块 对象时 得到X 方法作为“函数”而不是“方法”调用,它需要“绑定”到 模块 通过对象 绑定() 方法- const boundGetX = unboundGetX.bind(module); .
结论
现在你知道怎么做 这个 关键字的作品及其适用的不同上下文。您应该能够在需要时舒适地使用它。
概括
在本文中,您了解了以下内容:
- 什么
这个关键字在 Javascript 中? - 什么
这个关键字在节点中表示。 - 如何
这个关键字在全局和函数执行上下文中确定。 - 调用函数的不同方式及其关联方式
这个 - 如何控制值
这个使用称呼()和申请()方法。 - 如何使用
绑定()方法。 - 如何
这个表现在箭头函数中
词汇表
堆栈或调用堆栈:堆栈是遵循后进先出 (LIFO) 原则的数据结构。但是,执行堆栈是一个跟踪代码执行期间创建的所有执行上下文的堆栈。堆栈还将静态数据存储在 Javascript(变量和参考值)中。学到更多 这里
堆:堆是Javascript中用于存储动态数据的数据结构。这是存储所有 Javascript 对象的地方。学到更多 这里 .
词法作用域:读取此堆栈溢出 回答 为了更好地理解。
Javascript 严格模式: MDN
来自编辑的提示:有关 JavaScript 内部细节的更多信息,请不要错过同一作者的其他文章: JavaScript 类型和值,解释 , 和 解释 JavaScript 的执行上下文和堆栈 .

https://newsletter.openreplay.com/
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

浙公网安备 33010602011771号