JavaScript执行上下文

248 阅读3分钟

概念

举个例子,生活中,相同的话在不同的场合说可能会有不同的意思,而这个说话的场合就是我们说话的语境。同样对应在编程中, 对程序语言进行“解读”的时候,也必须在特定的语境中,这个语境就是javascript中的执行上下文。

总之:执行上下文就是javascript代码被解析和执行时所在环境的抽象概念。

类型

在js中,执行上下文分为以下三种:

全局执行上下文:只有一个,也就是浏览器对象(即window对象),this指向的就是这个全局对象。

函数执行上下文:有无数个,只有在函数被调用时才会被创建,每次调用函数都会创建一个新的执行上下文。

Eval函数执行上下文:js的eval函数执行其内部的代码会创建属于自己的执行上下文, 很少用而且不建议使用。

JS如何管理多个执行上下文

同时由于js是单线程的,所以不能同时干两件事,必须一个个去执行。

管理多个执行上下文靠的就是执行栈,也被叫做调用栈

特点:后进先出(LIFO)的结构。

作用:存储在代码执行期间的所有执行上下文。

var a = 1; // 1. 全局上下文环境
function bar(x) {
	console.log("bar");
	var b = 2;
	fn(x + b); // 3. fn上下文环境
}
function fn(c) {
	console.log(c);
}
bar(3); // 2. bar上下文环境

具体分析如下图

执行上下文的生命周期

执行上下文的生命周期也非常容易理解, 分为三个阶段:

  • 创建阶段
    • 确定this的值, 也就是绑定this;
      • 实际开发主要用到两种执行上下文为全局和函数, 那么绑定this在这两种上下文中也不同.
      • 全局执行上下文中, this指的就是全局对象, 浏览器环境指向window对象, nodejs中指向这个文件的module对象.
      • 函数执行上下文较为复杂, this的值取决于函数的调用方式. 具体有: 默认绑定、隐式绑定、显式绑定、new绑定、箭头函数.
    • 词法环境被创建;
    • 变量环境被创建.
  • 执行阶段
    • 变量赋值
    • 函数引用
    • 执行其他的代码
  • 销毁阶段:执行完毕出栈,等待回收被销毁

函数执行上下文较为复杂, this的值取决于函数的调用方式.

具体有: 默认绑定、隐式绑定、显式绑定、new绑定、箭头函数.

默认绑定: 当函数以普通函数调用的方式执行时

function showThis() {
    console.log(this);
}
showThis(); // 非严格模式下:window,严格模式下:undefined

隐式绑定: 当函数作为某个对象的方法调用时,this 指向调用该方法的对象。

const obj = {
    name: 'Alice',
    greet() {
        console.log(this.name);
    },
};
obj.greet(); // 输出: Alice,this 指向 obj

显式绑定: 使用 callapplybind 方法显式指定 this 的指向。

  • call: 函数立即执行,参数逐一传递。
  • apply: 函数立即执行,参数以数组形式传递。
  • bind: 返回一个新函数,this 被永久绑定,不会立即执行。
function showThis(message) {
    console.log(this.name, message);
}
const obj = { name: 'Alice' };

showThis.call(obj, 'Hello');  // 输出: Alice Hello
showThis.apply(obj, ['Hi']); // 输出: Alice Hi
const boundFunc = showThis.bind(obj, 'Hey');
boundFunc();                 // 输出: Alice Hey

new绑定

  • 创建一个新的空对象。
  • 将这个对象的 Prototype 绑定到函数的 prototype
  • 函数中的 this 指向这个新对象。
  • 如果函数没有显式返回对象,返回这个新对象。
function Person(name) {
    this.name = name;
}
const alice = new Person('Alice');
console.log(alice.name); // 输出: Alice,this 指向新创建的 alice 对象

箭头函数

  • 箭头函数的 this定义时的上下文决定,继承自外层的作用域,与调用方式无关。
  • 它不会创建自己的 this,所以不会受隐式、显式或 new 绑定影响。
const obj = {
    name: 'Alice',
    greet: () => {
        console.log(this.name); // this 是定义时的上下文,即全局对象
    },
};
obj.greet(); // 输出: undefined(全局对象中没有 name 属性)

function outer() {
    const arrowFunc = () => console.log(this);
    arrowFunc();
}
outer.call({ name: 'Bob' }); // 输出: { name: 'Bob' },继承外层作用域的 this