声明

本系列文章内容全部梳理自以下几个来源:

作为一个前端小白,入门跟着这几个来源学习,感谢作者的分享,在其基础上,通过自己的理解,梳理出的知识点,或许有遗漏,或许有些理解是错误的,如有发现,欢迎指点下。

PS:梳理的内容以《JavaScript权威指南》这本书中的内容为主,因此接下去跟 JavaScript 语法相关的系列文章基本只介绍 ES5 标准规范的内容、ES6 等这系列梳理完再单独来讲讲。

正文-执行上下文EC和变量对象VO

EC:Execution Context,中文翻译执行上下文,也有翻译成执行环境的。

VO:Variable object,中文翻译变量对象。

这两个概念很重要,涉及到作用域以及作用域链的原理。

执行上下文 EC

先说说Android中的上下文:

  • Android

Android 中也有上下文:Context,四大组件都是上下文,还有一个全局的 Application上下文。在 Android 中基本是以四大组件为界限,每创建一个四大组件,都会产生一个上下文,比如每个 Activity 都是独立的上下文。

在 Android 中,上下文 Context 的作用大体上用于标识各种资源的所属,要加载一张图片、创建一个 View、弹一个 Dialog 等等,你需要告诉系统,这些是谁发出的指令,要挂载到哪个上下文,这些资源依赖于上下文的生命周期。

所以才会出现,有时弹 Dialog 或者更新某个 View 时抛异常说 Context 已销毁,因为它需要挂载的上下文已经销毁了,那么就没有上下文来统筹管理这些资源了,自然会抛异常。

  • JavaScript

在 JavaScript 中,上下文是指执行上下文,通俗点理解,代码执行的上下文,所以也有翻译成执行环境,可以通俗的把它理解成一个对象,对象名 EC,表示代码的执行上下文。

既然理解成一个对象,那么就有它创建的时机,在 JavaScript 中,每当要执行不同类型的代码时,就会创建一个执行上下文 EC。

而代码的类型分三种:

  • 全局代码
  • 函数代码
  • eval()执行的代码

最后一种不讨论,全局代码就是指写在函数外的代码,在前端里,当 HTML 加载一个 js 文件时,全局代码就会被执行,那么在全局代码执行前就会先创建一个全局的执行上下文 EC,之后每调用一次函数,要执行函数内的代码时,会再创建一个函数执行上下文 EC。

也就是说,不讨论 eval 的话,那么在 JavaScript 有两种执行上下文,一种是全局执行上下文,一种是函数执行上下文。

而每次创建一个执行上下文时,都会将其放入一个栈结构,这个栈就称为执行上下文栈(ECS),也有翻译成执行环境栈。

所以执行 js 文件代码期间,这个栈底一直是全局执行上下文,直到 js 文件代码执行结束。全局代码执行过程中,每调用一次函数,新创建一个函数执行上下文,就放入栈内。

因此,栈顶就表示当前执行的代码,如果栈顶是全局执行上下文,表示正在执行全局代码;如果栈顶是函数执行上下文,表示正在执行函数内的代码。当函数执行结束时,这个函数执行上下文就从栈中移出。

那么执行上下文(EC)有什么用呢?

用途可多了,跟 Android 不一样,Android 里由于是各种资源的组合使用,但在 JavaScript 中更多的是嵌套函数的变量使用。所以,用途之一就是保存各个变量。

将 EC 理解成一个对象的话,它有两个属性,一个是变量对象(VO),另一个是作用域链(Scope Chain)。对于全局执行上下文,当 HTML 加载一个 js 文件时,就会创建一个全局 EC,此时会创建它的两个属性:变量对象和作用域链。之后,每调用一次函数,创建这次函数执行的上下文,函数内部的变量的使用就依赖于这个函数执行上下文中的变量对象和作用域链。

也就是说,内部函数之所以可以使用外部函数内的变量,之所以可以使用全局变量,都是依赖于当前这个内部函数的执行上下文。

而且,变量之所以会提前声明也是因为执行上下文的因素。这些当讲解了执行上下文 EC 的创建过程就清楚了。

变量对象 VO

变量对象只是一个抽象的概念,可以通俗的理解成保存当前上下文所有变量的对象。

在不同的执行上下文中,它有不同的具体表现。

在全局执行上下文中,变量对象 VO 的具体表现就是全局对象,因为所有的全局变量其实都是全局对象的属性,而变量对象 VO 的作用是要保存当前上下文中的所有变量,所以此时的变量对象 VO 实际上是指向的全局对象。

尤其在前端中,全局对象就是 window,所以全局执行上下文的变量对象 VO = window。

在函数执行上下文中,因为变量对象 VO 是要保存当前上下文中所有的变量,一个函数内的变量包括:形参变量、局部变量、自身函数对象引用变量、arguments、this。

针对函数执行上下文,为了保存这些变量,特意创建了一个对象,称它为活动对象 AO,函数内所需的变量就都保存在 AO 中,所以在函数执行上下文中,变量对象 VO 的具体表现也就是 AO。

小结:变量对象 VO 是一个抽象概念,用于保存当前执行上下文中所有的变量。所以在全局执行上下文中,因为全局对象已经保存着当前上下文所有的变量,所以 VO 在这里的具体实现就是全局对象。在函数执行上下文中,由于要保存函数形参、局部变量、自身函数对象引用变量、arguments、this,所以新创建了一个叫活动对象 AO 来保存,此时 VO 的具体实现就是 AO。

作用域链

每次函数调用时,都会创建一个函数执行上下文 EC,但其中的变量对象 VO 只保存着当前上下文中的变量而已,那么函数内如果需要使用到外部函数的变量,甚至是使用全局的变量时,此时就需要依赖于执行上下文的另一个属性:作用域链。

作用域链本质上,其实是将有嵌套层次关系的执行上下文的 VO 拼接起来。

所以大部分场景作用域链只有两个节点:当前函数执行上下文的 VO –> 全局执行上下文的 VO。所以函数内才可以根据作用域链访问全局内的变量。

当出现函数内再嵌套函数时,此时作用域链就会比较长:

内层函数执行上下文的 VO –> 外层函数执行上下文的 VO –> 全局执行上下文 VO。

至于作用域链是如何将有嵌套层次的执行上下文的 VO 拼接起来,需要借助函数对象的内部属性 [[Scope]],[[]]表示执行引擎为对象创建的内部属性,我们访问不了,也操作不了。具体原理在作用域链一节中讲解。


大家好,我是 dasu,欢迎关注我的公众号(dasuAndroidTv),公众号中有我的联系方式,欢迎有事没事来唠嗑一下,如果你觉得本篇内容有帮助到你,可以转载但记得要关注,要标明原文哦,谢谢支持~

前端入门16-JavaScript进阶之EC和VO的更多相关文章

  1. 前端基础之JavaScript进阶

    一.流程控制 if - else var a = 10; if (a >5){ console.log("yes"); }else { console.log("n ...

  2. 前端入门18-JavaScript进阶之作用域链

    声明 本系列文章内容全部梳理自以下几个来源: <JavaScript权威指南> MDN web docs Github:smyhvae/web Github:goddyZhao/Trans ...

  3. 前端入门17-JavaScript进阶之作用域

    声明 本系列文章内容全部梳理自以下几个来源: <JavaScript权威指南> MDN web docs Github:smyhvae/web Github:goddyZhao/Trans ...

  4. 4、JavaScript进阶篇①——基础语法

    一.认识JS 你知道吗,Web前端开发师需要掌握什么技术?也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HTML+CSS创建一个漂亮的页面,但这还不够,它只是静态页面 ...

  5. 结合个人经历总结的前端入门方法 (转自https://github.com/qiu-deqing/FE-learning)

    结合个人经历总结的前端入门方法 (https://github.com/qiu-deqing/FE-learning),里面有很详细的介绍. 之前一直想学习前端的,都不知道怎么下手都一年了啥也没学到, ...

  6. JavaScript进阶(一)

     OK接下来,我们再次梳理一遍js并且提高一个等级. 众所周知,web前端开发者需要了解html和css,会只用html和css创建一个漂亮的页 面,但是这肯定是不够的,因为它只是一个静态的页面,我们 ...

  7. 2019年Web前端入门的自学路线

    本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文.本文内容不定期更新. 我前几天写过一篇文章:<裸辞两个月,海投一个月 ...

  8. JavaScript进阶 - 第1章 系好安全带,准备启航

    第1章 系好安全带,准备启航 1-1让你认识JS 你知道吗,Web前端开发师需要掌握什么技术?也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HTML+CSS创建一个漂 ...

  9. JavaScript进阶之高阶函数篇

    JavaScript进阶之高阶函数篇 简介:欢迎大家来到woo爷说前端:今天给你们带来的是JavaScript进阶的知识,接下来的系列都是围绕着JavaScript进阶进行阐述:首先我们第一篇讲的是高 ...

随机推荐

  1. SEED实验——return-to-libc实验

    实验概述 本实验的学习目标是让学生获得缓冲区溢出攻击的一种有趣变体——return-to-libc攻击实验的亲身体验.这种攻击可以绕过目前在主要linux操作系统中实现的现有保护方案.利用缓冲区溢出漏 ...

  2. Java作业五(2017-10-15)

    /*3-6.程序员;龚猛*/ 1 package zhenshu; import java.util.Scanner; public class text { public static void m ...

  3. 安卓开发学习笔记(四):Android Stuidio无法实现隐式Intent是为什么?

    一.首先检查我们的代码: FirstActivity.java(主活动程序当中的代码):Button3监听器后面的代码就是我们隐式Intent的业务逻辑所在了,大家可以往下面看看,大概在代码的第57行 ...

  4. 字符串----HDU-1358

    题目大意:求字符串的前缀是否为周期串,若是,打印出循环节的长度以及循环次数. 这道题考察的是KMP算法中next数组的应用,必须理解透next[]数组代表的含义才t能通过它解决这道题.思路是先构造出 ...

  5. [Swift]LeetCode1002. 查找常用字符 | Find Common Characters

    Given an array A of strings made only from lowercase letters, return a list of all characters that s ...

  6. SecureCRT8.1发送命令到多个或所有linux终端

  7. GenerationType四中类型

    https://blog.csdn.net/u011781521/article/details/72210980 JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO. ...

  8. 受到 1 万点暴击,二狗子被 DDoS 攻击的惨痛经历

    二狗子的遭遇 “好消息,好消息,免费 DDoS 攻击软件上线了,性感黑客在线攻击,帮您攻克所有商业难题.”二狗子不知道在看着什么网站,新买的 Mac 中发出热闹的声音. 二狗子想知道“DDoS 是什么 ...

  9. 【转】ret,retf,iret的区别

    ret RET, and its exact synonym RETN, pop IP or EIP from the stack and transfer control to the new ad ...

  10. .net core高性能通讯开源组件BeetleX

    BeetleX beetleX是基于dotnet core实现的轻量级高性能的TCP通讯组件,使用方便.性能高效和安全可靠是组件设计的出发点!开发人员可以在Beetlx组件的支持下快带地构建高性能的T ...