javascript深入之执行上下文
  h9htfs4cnhmS 2023年12月02日 22 0

一、执行上下文

1.什么是执行上下文?

简单来说,执行上下文就是当前javascript代码解析和执行时的环境的抽象概念。javascript任何代码的运行都是在执行上下文中进行的。

2.执行上下文的类型

  • 全局执行下文:全局执行上下文是最基础的执行上下文。不存在于任何函数中的代码都属于全局执行上下文。全局执行上下文做了两件事:1.创建一个变量对象,将window对象赋值给该变量对象(变量对象=window)。2.确定this的指向。全局执行上下文只会存在一个。全局上下文只有在应用关闭或者浏览器关闭的时候才会被销毁。
  • 函数执行上下文:每个函数都有自己的执行上下文,当函数被调用时才会创建执行上下文。函数每次调用的时候,都会创建一个新的执行上下文。
  • Eval执行上下文:使用eval函数调用的代码也会创建自己的执行上下文。

3.执行上下文的生命周期

执行上下文的生命周期分为三个阶段:创建阶段  执行阶段 → 回收阶段。

1.创建阶段:

在调用函数,但未执行任何代码前,会创建执行上下文,紧接着执行上下文做了三件事:

  • 创建变量对象:会使用函数的形参初始化arguments对象,将arguments对象作为变量对象的初始化属性。提升变量声明和函数声明。在函数中,js会使用活动对象(activation object)来作为变量对象。
  • 创建作用域链:创建作用域链在创建变量对象之后,因为作用域链会包含变量对象,可以将作用域链看做是变量对象的一个链表,作用域链的第一个变量对象始终会是当前执行上下文的变量对象,下一个对象来自父级函数的变量对象,全局执行上下文的变量对象(window)始终存在作用域链的底部。作用域链的作用是按顺序查找变量。查找变量时会从作用域链的顶端开始逐一向后查找,直至到全局执行上下文的变量对象。在此当中找到了则会直接返回该变量,如果没有找到则会报错(Reference Error)。
  • 确定this的指向

2.执行阶段:

变量赋值,执行代码。

3.回收阶段:

执行上下文执行完毕后,会从执行上下文栈中弹出,等待被回收。

二、执行上下文栈

全局执行上下文只有一个,但是函数执行上下文却会有很多个,那么JavaScript是怎么来管理的呢?答案是:执行上下文栈(Execution Context Stack)。

我们可以将执行上下文栈看做是一个具体的对象:

EcStack = [];

当启动程序的时候,首先执行的是全局代码,所以会创建全局执行上下文,并将全局执行上下文压入执行上下文栈。

EcStack = [
  globalContext
];

当其它js代码运行时,执行栈会怎么变化呢?我们来看下面这个例子:

var a = 1;

function foo() {
  console.log(a);
}

function bar() {
  foo();
}

bar();

执行上下文栈:

  1. 调用bar函数,创建了bar函数的执行上下文,添加进执行上下文栈
  2. 在执行bar函数代码时,又遇到了foo函数,所以又会创建foo函数的执行上下文,添加进执行上下文栈
  3. 然后foo函树中又遇到log函数,则又会创建log函数的执行上下文
//调用bar函数
EcStack.push(barContext);

//调用foo函数
EcStack.push(fooContext);

//调用log函数
EcStack.push(logContext);

//log函数执行完毕
EcStack.pop(logContext);

//foo函数执行完毕
EcStack.pop(fooContext);

//bar函数执行完毕
EcStack.pop(barContext);

我们再来看一个例子:

var a = 1;

function foo() {
  function bar() {
    console.log(a);
  }
  return bar;
}

var func = foo();
func();

那现在是怎么向执行上下文栈中添加执行上下文的呢?

首先会调用foo函数,那么就会创建foo函数的执行上下文并添加到执行上下文栈中。foo函数中声明了bar函数,但是没有直接调用,而是将bar函数返回并赋值给func变量,然后调用了func。这时,才会创建func的执行上下文。

//调用foo
EcStack.push(fooContext);

//foo执行完毕
EcStack.pop(fooContext);

//调用func
EcStack.push(funcContext);

//func执行完毕
ExStack.pop(funcContext);

举这个例子是为了强调一点,执行上下文是在函数被调用时生成的。执行上下文执行完毕后,则会被弹出执行上下文栈,等待被回收。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月02日 0

暂无评论

h9htfs4cnhmS