执行上下文指的是代码在执行时的运行环境或作用域。

# 执行上下文类型:

  • 1、全局执行上下文 任何不在函数内部的代码都在全局上下文中,执行两件事:
    • (1)创建全局的 window 对象
    • (2)设置 this 的值等于全局对象 一个程序中只有一个全局执行上下文
  • 2、函数执行上下文:函数在被调用时创建
  • 3、Eval 函数执行上下文

# 执行栈

后进先出的栈,执行程序时,会创建全局的执行上下文并且压入当前执行栈,每当调用一个函数,就会为该函数创建一个新的执行上下文并压入栈。

# 创建执行上下文

(1)创建阶段【调用函数时,在执行函数之前】

  • 1、创建作用域链

  • 2、创建 variable object,并在 variable object 上创建变量、函数和参数

    • 1、创建 arguments object
    • 2、扫描上下文获取函数声明,找到的新函数,在 variable object 中创建对应属性,已有函数名则覆盖;
    • 3、扫描上下文获取变量声明,找到新的变量,在 variable object 中创建新的属性,初始化为 undefined,已存在则忽略

例如代码:

function foo(i) {
  var a = "hello";
  var b = function privateB() {};
  function c() {}
}

foo(22);
1
2
3
4
5
6
7

在调用 foo(2)时,创建上下文阶段:

fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: undefined,
        b: undefined
    },
    this: { ... }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 3、确定 this 的值
    • 1、在全局执行上下文中,this 的值指向全局对象。(在浏览器中,this 引用 Window 对象)。
    • 2、在函数执行上下文中,this 的值取决于该函数是如何被调用的。如果它被一个引用对象调用,那么 this 会被设置成那个对象,否则 this 的值被设置为全局对象或者 undefined(在严格模式下)
let foo = {
  baz: function() {
    console.log(this);
  },
};

foo.baz(); // 'this' 引用 'foo', 因为 'baz' 被
// 对象 'foo' 调用

let bar = foo.baz;

bar(); // 'this' 指向全局 window 对象,因为
// 没有指定引用对象
1
2
3
4
5
6
7
8
9
10
11
12
13

(2)执行阶段

  • 1、分配值,引用函数和解释、执行代码

代码执行后

fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: 'hello',
        b: pointer to function privateB()
    },
    this: { ... }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 题目练习

以下代码打印结果是什么?

(function() {
  console.log(typeof foo);
  console.log(typeof bar);

  var foo = "hello";
  var bar = function() {
    return "world";
  };

  function foo() {
    return "hello";
  }
})();
1
2
3
4
5
6
7
8
9
10
11
12
13

回答:

上面为自执行函数,在函数执行前,先创建执行上下文,先处理函数声明,声明了 foo 函数,然后处理变量声明,虽然有 var foo,因为 foo 之前已经声明过函数,所以变量声明不在生效,而 bar 时变量声明为 undefined,所以最终的结果是: function,undefined

# 相关文章