this:从JavaScript执行上下文讲解this是什么

152 阅读4分钟

JavaScript中的this是什么

执行上下文中包括了变量环境,词法环境,外部环境以及this

image.png 从图中可以看出this是与执行上下文绑定的。

this既不指向函数自身也不指向函数的词法作用域。this就是执行上下文的一个属性,它指向的是执行上下文对象,this是在函数调用时才发生的绑定,它指向什么完全取决于函数在哪里被调用

this根据执行上下文的种类可以划分为下面三类

1.全局执行上下文的this

在全局执行上下文中,this 的值通常指向全局对象。在浏览器中,全局对象是 window 对象。这是因为全局执行上下文是在全局作用域中执行的,而在浏览器中,全局作用域就是 window 对象的作用域。

image.pngNode.js 等非浏览器环境中,全局对象可能是 global

如果在严格模式下执行代码(通过在脚本或函数的顶部添加 'use strict';),全局执行上下文中的 this 不再指向全局对象,而是为 undefined。在非严格模式下,默认情况下是指向全局对象的。

2.函数执行上下文中的this

在函数执行上下文中,this 的值取决于函数被调用的方式。不同的调用方式会导致 this 指向不同的对象或值。有以下几种情况:

  • 普通函数调用: 当函数作为普通函数调用时,this 指向全局对象(在浏览器中通常是 window)。
function foo() {
  console.log(this); // Window {window: Window, self: Window, document: document, name: '', location: Location, …}
}
foo();
  • 对象方法调用: 当函数作为对象的方法调用时,this指向调用该方法的对象。
const obj = {
  bar: function () {
    console.log(this); // {bar: ƒ}
  },
};
obj.bar();
  • 构造函数调用: 当函数被用作构造函数(通过 new 关键字调用)时this指向新创建的实例对象。
function MyClass() {
  console.log(this); // MyClass {}
}

const myInstance = new MyClass();
  • 使用 call、apply 或 bind 显式指定 this: 使用 callapplybind 方法可以显式地指定函数执行时的 this 值。
function myFunction() {
  console.log(this); // {prop: 'Custom object'}
}

var customObject = { prop: "Custom object" };

myFunction.call(customObject); // this 指向 customObject
  • 箭头函数中this 的值是在创建函数时确定的,而不是在运行时。箭头函数没有自己的 this,它继承自父级作用域。因此,在箭头函数中,this 的值与外部的执行上下文相关。

3.eval执行上下文中的this(尽量不要用eval)

this 的值通常取决于代码的执行环境。如果代码在全局范围内执行,this 将指向全局对象(在浏览器环境中通常是 window)。

image.png 在严格模式下执行的eval代码,this 的值将是 undefined

慎用 eval 的主要原因是它会引入安全性和性能方面的问题。

以下是一些使用 eval 需要谨慎的原因:

1.安全性问题:

  • eval可以执行任意的 JavaScript 代码,包括字符串中可能包含的恶意代码。
  • 如果动态地将用户提供的数据传递给 eval,存在被注入恶意代码的风险,这可能导致安全漏洞。

2.性能问题:

  • eval 的使用可能导致性能下降,因为它迫使 JavaScript 引擎在运行时解析和编译字符串,而不是在代码加载时进行静态分析。
  • 静态分析有助于更好的优化和代码执行。

3.可读性和维护性:

  • 使用 eval可以使代码更难以理解和维护,因为它引入了动态生成和执行的代码片段,使得代码的行为变得不透明。
  • 可能会导致难以调试的问题,因为代码的结构和逻辑在运行时才确定。

4.跨浏览器兼容性问题:

  • eval的行为在不同的 JavaScript 引擎中可能会有细微差异,导致跨浏览器兼容性问题。

5.限制代码优化:

  • 使用 eval可能会限制 JavaScript 引擎的一些优化,因为引擎无法在运行时确定代码的结构。

如果没有十分明确的原因和必要,最好避免使用 eval。