登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
Gitee 2025 年度开源项目评选中
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
3
Star
45
Fork
21
DreamCoders
/
CoderGuide
代码
Issues
1169
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
JavaScript中执行上下文和执行栈是什么?
待办的
#IAG9PL
陌生人
拥有者
创建于
2024-07-29 16:07
<h2>一、执行上下文</h2><p>简单的来说,执行上下文是一种对<code>Javascript</code>代码执行环境的抽象概念,也就是说只要有<code>Javascript</code>代码运行,那么它就一定是运行在执行上下文中</p><p>执行上下文的类型分为三种:</p><ul><li>全局执行上下文:只有一个,浏览器中的全局对象就是 <code>window</code>对象,<code>this</code> 指向这个全局对象</li><li>函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文</li><li>Eval 函数执行上下文: 指的是运行在 <code>eval</code> 函数中的代码,很少用而且不建议使用</li></ul><p>下面给出全局上下文和函数上下文的例子:</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/46deb05d-f7d3-4d1f-88d3-84aaf66810f7.png" alt="" data-href="" style=""/></p><p>紫色框住的部分为全局上下文,蓝色和橘色框起来的是不同的函数上下文。只有全局上下文(的变量)能被其他任何上下文访问</p><p>可以有任意多个函数上下文,每次调用函数创建一个新的上下文,会创建一个私有作用域,函数内部声明的任何变量都不能在当前函数作用域外部直接访问</p><h2>二、生命周期</h2><p>执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段</p><h3>创建阶段</h3><p>创建阶段即当函数被调用,但未执行任何其内部代码之前</p><p>创建阶段做了三件事:</p><ul><li>确定 this 的值,也被称为 <code>This Binding</code></li><li>LexicalEnvironment(词法环境) 组件被创建</li><li>VariableEnvironment(变量环境) 组件被创建</li></ul><p>伪代码如下:</p><pre><code class="language-js">ExecutionContext = { ThisBinding = <this value>, // 确定this LexicalEnvironment = { ... }, // 词法环境 VariableEnvironment = { ... }, // 变量环境 }</code></pre><h4>This Binding</h4><p>确定<code>this</code>的值我们前面讲到,<code>this</code>的值是在执行的时候才能确认,定义的时候不能确认</p><h4>词法环境</h4><p>词法环境有两个组成部分:</p><ul><li>全局环境:是一个没有外部环境的词法环境,其外部环境引用为null,有一个全局对象,this 的值指向这个全局对象</li><li>函数环境:用户在函数中定义的变量被存储在环境记录中,包含了arguments 对象,外部环境的引用可以是全局环境,也可以是包含内部函数的外部函数环境</li></ul><p>伪代码如下:</p><pre><code class="language-js">GlobalExectionContext = { // 全局执行上下文 LexicalEnvironment: { // 词法环境 EnvironmentRecord: { // 环境记录 Type: "Object", // 全局环境 // 标识符绑定在这里 outer: <null> // 对外部环境的引用 } } FunctionExectionContext = { // 函数执行上下文 LexicalEnvironment: { // 词法环境 EnvironmentRecord: { // 环境记录 Type: "Declarative", // 函数环境 // 标识符绑定在这里 // 对外部环境的引用 outer: <Global or outer function environment reference> } }</code></pre><h4>变量环境</h4><p>变量环境也是一个词法环境,因此它具有上面定义的词法环境的所有属性</p><p>在 ES6 中,词法环境和变量环境的区别在于前者用于存储函数声明和变量( <code>let</code> 和 <code>const</code> )绑定,而后者仅用于存储变量( <code>var</code> )绑定</p><p>举个例子</p><pre><code class="language-js">let a = 20; const b = 30; var c; function multiply(e, f) { var g = 20; return e * f * g; } c = multiply(20, 30);</code></pre><p>执行上下文如下:</p><pre><code class="language-js">GlobalExectionContext = { ThisBinding: <Global Object>, LexicalEnvironment: { // 词法环境 EnvironmentRecord: { Type: "Object", // 标识符绑定在这里 a: < uninitialized >, b: < uninitialized >, multiply: < func > } outer: <null> }, VariableEnvironment: { // 变量环境 EnvironmentRecord: { Type: "Object", // 标识符绑定在这里 c: undefined, } outer: <null> } } FunctionExectionContext = { ThisBinding: <Global Object>, LexicalEnvironment: { EnvironmentRecord: { Type: "Declarative", // 标识符绑定在这里 Arguments: {0: 20, 1: 30, length: 2}, }, outer: <GlobalLexicalEnvironment> }, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", // 标识符绑定在这里 g: undefined }, outer: <GlobalLexicalEnvironment> } }</code></pre><p>留意上面的代码,<code>let</code>和<code>const</code>定义的变量<code>a</code>和<code>b</code>在创建阶段没有被赋值,但<code>var</code>声明的变量从在创建阶段被赋值为<code>undefined</code></p><p>这是因为,创建阶段,会在代码中扫描变量和函数声明,然后将函数声明存储在环境中</p><p>但变量会被初始化为<code>undefined</code>(<code>var</code>声明的情况下)和保持<code>uninitialized</code>(未初始化状态)(使用<code>let</code>和<code>const</code>声明的情况下)</p><p>这就是变量提升的实际原因</p><h3>执行阶段</h3><p>在这阶段,执行变量赋值、代码执行</p><p>如果 <code>Javascript</code> 引擎在源代码中声明的实际位置找不到变量的值,那么将为其分配 <code>undefined</code> 值</p><h3>回收阶段</h3><p>执行上下文出栈等待虚拟机回收执行上下文</p><h2>二、执行栈</h2><p>执行栈,也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/c3bb48b2-7b62-4158-a2fc-7e5579ca3626.png" alt="" data-href="" style=""/></p><p>当<code>Javascript</code>引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中</p><p>每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中</p><p>引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文</p><p>举个例子:</p><pre><code class="language-js">let a = 'Hello World!'; function first() { console.log('Inside first function'); second(); console.log('Again inside first function'); } function second() { console.log('Inside second function'); } first(); console.log('Inside Global Execution Context');</code></pre><p>转化成图的形式</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/5c6dd2a6-462a-4cc9-ab10-e0a58105c763.png" alt="" data-href="" style=""/></p><p>简单分析一下流程:</p><ul><li>创建全局上下文请压入执行栈</li><li><code>first</code>函数被调用,创建函数执行上下文并压入栈</li><li>执行<code>first</code>函数过程遇到<code>second</code>函数,再创建一个函数执行上下文并压入栈</li><li><code>second</code>函数执行完毕,对应的函数执行上下文被推出执行栈,执行下一个执行上下文<code>first</code>函数</li><li><code>first</code>函数执行完毕,对应的函数执行上下文也被推出栈中,然后执行全局上下文</li><li>所有代码执行完毕,全局上下文也会被推出栈中,程序结束</li></ul>
<h2>一、执行上下文</h2><p>简单的来说,执行上下文是一种对<code>Javascript</code>代码执行环境的抽象概念,也就是说只要有<code>Javascript</code>代码运行,那么它就一定是运行在执行上下文中</p><p>执行上下文的类型分为三种:</p><ul><li>全局执行上下文:只有一个,浏览器中的全局对象就是 <code>window</code>对象,<code>this</code> 指向这个全局对象</li><li>函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文</li><li>Eval 函数执行上下文: 指的是运行在 <code>eval</code> 函数中的代码,很少用而且不建议使用</li></ul><p>下面给出全局上下文和函数上下文的例子:</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/46deb05d-f7d3-4d1f-88d3-84aaf66810f7.png" alt="" data-href="" style=""/></p><p>紫色框住的部分为全局上下文,蓝色和橘色框起来的是不同的函数上下文。只有全局上下文(的变量)能被其他任何上下文访问</p><p>可以有任意多个函数上下文,每次调用函数创建一个新的上下文,会创建一个私有作用域,函数内部声明的任何变量都不能在当前函数作用域外部直接访问</p><h2>二、生命周期</h2><p>执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段</p><h3>创建阶段</h3><p>创建阶段即当函数被调用,但未执行任何其内部代码之前</p><p>创建阶段做了三件事:</p><ul><li>确定 this 的值,也被称为 <code>This Binding</code></li><li>LexicalEnvironment(词法环境) 组件被创建</li><li>VariableEnvironment(变量环境) 组件被创建</li></ul><p>伪代码如下:</p><pre><code class="language-js">ExecutionContext = { ThisBinding = <this value>, // 确定this LexicalEnvironment = { ... }, // 词法环境 VariableEnvironment = { ... }, // 变量环境 }</code></pre><h4>This Binding</h4><p>确定<code>this</code>的值我们前面讲到,<code>this</code>的值是在执行的时候才能确认,定义的时候不能确认</p><h4>词法环境</h4><p>词法环境有两个组成部分:</p><ul><li>全局环境:是一个没有外部环境的词法环境,其外部环境引用为null,有一个全局对象,this 的值指向这个全局对象</li><li>函数环境:用户在函数中定义的变量被存储在环境记录中,包含了arguments 对象,外部环境的引用可以是全局环境,也可以是包含内部函数的外部函数环境</li></ul><p>伪代码如下:</p><pre><code class="language-js">GlobalExectionContext = { // 全局执行上下文 LexicalEnvironment: { // 词法环境 EnvironmentRecord: { // 环境记录 Type: "Object", // 全局环境 // 标识符绑定在这里 outer: <null> // 对外部环境的引用 } } FunctionExectionContext = { // 函数执行上下文 LexicalEnvironment: { // 词法环境 EnvironmentRecord: { // 环境记录 Type: "Declarative", // 函数环境 // 标识符绑定在这里 // 对外部环境的引用 outer: <Global or outer function environment reference> } }</code></pre><h4>变量环境</h4><p>变量环境也是一个词法环境,因此它具有上面定义的词法环境的所有属性</p><p>在 ES6 中,词法环境和变量环境的区别在于前者用于存储函数声明和变量( <code>let</code> 和 <code>const</code> )绑定,而后者仅用于存储变量( <code>var</code> )绑定</p><p>举个例子</p><pre><code class="language-js">let a = 20; const b = 30; var c; function multiply(e, f) { var g = 20; return e * f * g; } c = multiply(20, 30);</code></pre><p>执行上下文如下:</p><pre><code class="language-js">GlobalExectionContext = { ThisBinding: <Global Object>, LexicalEnvironment: { // 词法环境 EnvironmentRecord: { Type: "Object", // 标识符绑定在这里 a: < uninitialized >, b: < uninitialized >, multiply: < func > } outer: <null> }, VariableEnvironment: { // 变量环境 EnvironmentRecord: { Type: "Object", // 标识符绑定在这里 c: undefined, } outer: <null> } } FunctionExectionContext = { ThisBinding: <Global Object>, LexicalEnvironment: { EnvironmentRecord: { Type: "Declarative", // 标识符绑定在这里 Arguments: {0: 20, 1: 30, length: 2}, }, outer: <GlobalLexicalEnvironment> }, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", // 标识符绑定在这里 g: undefined }, outer: <GlobalLexicalEnvironment> } }</code></pre><p>留意上面的代码,<code>let</code>和<code>const</code>定义的变量<code>a</code>和<code>b</code>在创建阶段没有被赋值,但<code>var</code>声明的变量从在创建阶段被赋值为<code>undefined</code></p><p>这是因为,创建阶段,会在代码中扫描变量和函数声明,然后将函数声明存储在环境中</p><p>但变量会被初始化为<code>undefined</code>(<code>var</code>声明的情况下)和保持<code>uninitialized</code>(未初始化状态)(使用<code>let</code>和<code>const</code>声明的情况下)</p><p>这就是变量提升的实际原因</p><h3>执行阶段</h3><p>在这阶段,执行变量赋值、代码执行</p><p>如果 <code>Javascript</code> 引擎在源代码中声明的实际位置找不到变量的值,那么将为其分配 <code>undefined</code> 值</p><h3>回收阶段</h3><p>执行上下文出栈等待虚拟机回收执行上下文</p><h2>二、执行栈</h2><p>执行栈,也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/c3bb48b2-7b62-4158-a2fc-7e5579ca3626.png" alt="" data-href="" style=""/></p><p>当<code>Javascript</code>引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中</p><p>每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中</p><p>引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文</p><p>举个例子:</p><pre><code class="language-js">let a = 'Hello World!'; function first() { console.log('Inside first function'); second(); console.log('Again inside first function'); } function second() { console.log('Inside second function'); } first(); console.log('Inside Global Execution Context');</code></pre><p>转化成图的形式</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/5c6dd2a6-462a-4cc9-ab10-e0a58105c763.png" alt="" data-href="" style=""/></p><p>简单分析一下流程:</p><ul><li>创建全局上下文请压入执行栈</li><li><code>first</code>函数被调用,创建函数执行上下文并压入栈</li><li>执行<code>first</code>函数过程遇到<code>second</code>函数,再创建一个函数执行上下文并压入栈</li><li><code>second</code>函数执行完毕,对应的函数执行上下文被推出执行栈,执行下一个执行上下文<code>first</code>函数</li><li><code>first</code>函数执行完毕,对应的函数执行上下文也被推出栈中,然后执行全局上下文</li><li>所有代码执行完毕,全局上下文也会被推出栈中,程序结束</li></ul>
评论 (
0
)
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
标签
Html/JS/CSS
未设置
标签管理
里程碑
未关联里程碑
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
未关联
master
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
1
https://gitee.com/DreamCoders/CoderGuide.git
git@gitee.com:DreamCoders/CoderGuide.git
DreamCoders
CoderGuide
CoderGuide
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册