资讯专栏INFORMATION COLUMN

JS学习系列 05 - 执行上下文

Hegel_Gu / 1447人阅读

摘要:根据顺序我们也可以看出来,想要理解作用域链,执行上下文是我们碰到的第一个坎。

在我们前面理解了作用域之后,“作用域链”这个概念就产生了。那么作用域链是什么意思,它又是怎么形成的,跟哪些概念有关系,这就是我接下来几章想和大家探讨的内容:执行上下文、变量对象和作用域链。根据顺序我们也可以看出来,想要理解作用域链,执行上下文是我们碰到的第一个坎。

这一章我们就来讨论一下到底什么是执行上下文

1. 定义

当 JS 引擎开始执行预编译生成的代码时,就会进入到一个执行上下文(Executable Code - 简称 EC)。

在 ECMA 标准规范里并没有从技术角度去定义 EC 的具体类型和结构,这个是在实现 ECMAScript 引擎时需要考虑的问题。

但是在逻辑上,我们可以将活动的执行上下文看成一个栈结构。栈底部永远是全局上下文(global context),而顶部就是当前活动的执行上下文。执行到当前代码时,上下文入栈,执行完毕后,上下文出栈。

2. 可执行代码有几种

前面说到当引擎执行到可执行代码的时候,就会将当前上下文压入上下文栈中。那么可执行的代码又分为几种?

在这里,我们先假设定义执行上下文栈是一个数组:

EC = [];

第一种可执行代码 -- 全局代码:
全局类型代码是在加载外部的 js 文件或者本地 标签中的代码。
注意,在全局代码中,并不包含定义在全局环境 function 内的代码

程序启动后进入初始化全局环境:

EC = [
    globalContext
];

第二种可执行代码 -- 函数代码:
当定义的函数被执行时,就进入了函数代码,当前函数上下文被压入 EC 栈中。
注意,在函数代码中,也不包含定义在该函数内部环境 function 内的代码。

例如:

var a = 10;

function foo () {
  var b = 20;
  
  foo();
}

foo();

这个例子中的 EC 是什么样子的呢?

// 初始化
EC = [
  globalContext
];

// 第一次调用 foo 函数
EC = [
   functionContext,
  globalContext
];

// 在 foo 内递归调用自己
EC = [
   functionContext - recursively,
   functionContext,
  globalContext
];

// 继续递归调用自己
EC = [
  ......
   functionContext - recursively2,
   functionContext - recursively,
   functionContext,
  globalContext
];

// 递归会不断调用下去,因为没有结束条件,所以这是一个死循环
// 所以,EC 只会不断增加新的上下文,但是却不会退出

只有每次 return 的时候,才会退出当前执行上下文,相应上下文会从栈中弹出,栈指针会自动移动位置。

注意,当函数没有明确指明 return 什么的时候,默认 return undefined

如果有抛出的异常没有被截获的话,也有可能从一个或多个执行上下文中退出。当所有代码执行完以后,EC 中只会包含全局上下文(global context),当程序退出以后,全局上下文也会退出。

第三种可执行代码 -- eval 代码:
eval 函数在调用的时候会产生上下文。
例如:

eval("var a = 10");

(function foo () {
  eval("var b = 20");
}());

alert(a);    // 10
alert(b);    // ReferenceError,b is not defined 

这个例子中 EC 的变化如下:

// 初始化
EC = [
  globalContext
];

// eval("var a = 10");
EC = [
  evalContext,
  globalContext
];

// eval 执行完毕
EC = [
  globalContext
];

// 立即执行函数 foo
EC = [
   functionContext,
  globalContext
];

// eval("var b = 20");
EC = [
  evalContext,
   functionContext,
  globalContext
];

// eval 执行完毕
EC = [
   functionContext,
  globalContext
];

// foo 执行完毕
EC = [
  globalContext
];

这就是一个典型的逻辑调用上下文栈

在 setTimeout 和 setInterval 函数中的第一个参数也可以传入代码字符串,但是这个一般不会这么去用,所以这里也就不讨论了。

3. 结论

执行上下文环境是我们了解变量对象作用域链的基础,大家一定要好好理解(其实也并不难),下一节我们来讨论变量对象,相信会让大家有一定的收获。

欢迎关注我的公众号

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81776.html

相关文章

  • Day05 - Flex 实现可伸缩的图片墙 中文指南

    摘要:实现可伸缩的图片墙中文指南作者简介是推出的一个天挑战。现在你看到的是这系列指南的第篇。完整指南在从零到壹全栈部落。实现效果点击任意一张图片,图片展开,同时从图片上下两方分别移入文字。 Day05 - Flex 实现可伸缩的图片墙 中文指南 作者:©liyuechun 简介:JavaScript30 是 Wes Bos 推出的一个 30 天挑战。项目免费提供了 30 个视频教程、30 ...

    zhangfaliang 评论0 收藏0
  • 【Step-By-Step】一周面试题深入解析 / 周刊02

    摘要:关于点击进入项目是我于开始的一个项目,每个工作日发布一道面试题。即使这个时间周期内,小明取得多次满分。创建作用域链在执行期上下文的创建阶段,作用域链是在变量对象之后创建的。这种一层一层的关系,就是作用域链。 关于【Step-By-Step】 Step-By-Step (点击进入项目) 是我于 2019-05-20 开始的一个项目,每个工作日发布一道面试题。每个周末我会仔细阅读大家的答...

    ixlei 评论0 收藏0
  • 【Step-By-Step】一周面试题深入解析 / 周刊02

    摘要:关于点击进入项目是我于开始的一个项目,每个工作日发布一道面试题。即使这个时间周期内,小明取得多次满分。创建作用域链在执行期上下文的创建阶段,作用域链是在变量对象之后创建的。这种一层一层的关系,就是作用域链。 关于【Step-By-Step】 Step-By-Step (点击进入项目) 是我于 2019-05-20 开始的一个项目,每个工作日发布一道面试题。每个周末我会仔细阅读大家的答...

    BDEEFE 评论0 收藏0
  • 听飞狐聊JavaScript设计模式系列13

    摘要:介一回聊状态模式,官方描述允许一个对象在其内部状态改变时改变它的行为。有限状态机有限状态机是一个非常有用的模型,可以模拟世界上大部分事物。这个是官方说法,简单说,她有三个特征,状态总数是有限的。,任一时刻,只处在一种状态之中。 本回内容介绍 上一回聊了聊组合模式(Composite),用组合模式模拟了个图片库,聊了递归。介一回聊状态模式(State),官方描述允许一个对象在其内部状态改...

    linkin 评论0 收藏0

发表评论

0条评论

Hegel_Gu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<