icon
预编译&执行上下文

预编译&执行上下文

预编译

JavaScript 在执行代码之前会进行预编译(预处理),主要包括:

  1. 变量提升(Hoisting)
    • var 声明的变量会被提升到作用域顶部
    • 函数声明会被完全提升
    • let/const 存在暂时性死区(TDZ)
// var 变量提升
console.log(a); // undefined
var a = 1;

// 等价于
var a;
console.log(a); // undefined
a = 1;

// 函数声明提升
foo(); // 'hello'
function foo() {
  console.log('hello');
}

// let/const 暂时性死区
console.log(b); // ReferenceError
let b = 2;
  1. 函数提升优先级
    • 函数声明优先级高于变量声明
    • 同名时函数会覆盖变量
console.log(foo); // [Function: foo]
var foo = 1;
function foo() {}

执行上下文(Execution Context)

执行上下文是 JavaScript 代码执行时的环境,包含三个重要组成部分:

  1. 变量对象(VO)/活动对象(AO)

    • 存储变量、函数声明和形参
    • 在函数执行时,VO 变为 AO
  2. 作用域链(Scope Chain)

    • 由当前执行上下文的变量对象和所有父级执行上下文的变量对象组成
    • 用于变量查找
  3. this 指向

    • 在函数执行时确定
function outer() {
  var a = 1;
  function inner() {
    console.log(a); // 通过作用域链查找
  }
  inner();
}
outer();

执行上下文的创建过程

  1. 创建阶段

    • 创建变量对象
    • 建立作用域链
    • 确定 this 指向
  2. 执行阶段

    • 变量赋值
    • 函数引用
    • 执行代码
function test(a, b) {
  var c = 1;
  function d() {}
  var e = function() {};
}

// 创建阶段(伪代码)
AO = {
  arguments: {
    0: a,
    1: b,
    length: 2
  },
  a: undefined,
  b: undefined,
  c: undefined,
  d: function d() {},
  e: undefined
}

// 执行阶段
AO = {
  arguments: {
    0: a,
    1: b,
    length: 2
  },
  a: 1,
  b: 2,
  c: 1,
  d: function d() {},
  e: function() {}
}

全局执行上下文

  • 全局对象(浏览器中是 window)
  • 全局变量和函数
  • this 指向全局对象
// 全局执行上下文
var globalVar = 'global';
function globalFunc() {
  console.log('global function');
}

函数执行上下文

  • 每次函数调用都会创建新的执行上下文
  • 函数执行完毕后,执行上下文被销毁
function test() {
  var localVar = 'local';
  console.log(localVar);
}
test(); // 创建函数执行上下文
test(); // 再次创建新的函数执行上下文