作用域和执行上下文

首先我们先看一副图


准确的说js的编译阶段和执行阶段不像传统的编译型语言,并没有分的很清楚。

在程序中我们把语言分为解释型语言编译型语言
解释型语言:在运行的时候将程序翻译成机器语言,所以运行速度相对于编译型语言要慢。
编译型语言:编译型语言在程序执行之前,有一个单独的编译过程,将程序翻译成机器语言,以后执行这个程序的时候,就不用再进行翻译了。
尽管 JavaScript 一般被划分到“动态”或者“解释型”语言的范畴,但是其实它是一个编译型语言。它 不是 像许多传统意义上的编译型语言那样预先被编译好,编译的结果也不能在各种不同的分布式系统间移植。
传统的编译过程大致分为:

  1. 分词/词法分析: 将一连串字符打断成(对于语言来说)有意义的片段
  2. 解析: 生成抽象语法树
  3. 代码生成:将抽象语法树转换为计算机可识别的可执行的代码
    但是JS与其他语言不同,JavaScript 的编译过程不是发生在构建之前的。
    对于 JavaScript 来说,大部分情况下编译发生在代码执行前的几微秒(甚至更短!)的时 间内。任何 JavaScript 代码片段在执行前都要进行编译(通常就在执行前)。因此, JavaScript 编译器首先会对 var a = 2; 这段程序进行编译,然后做好执行它的准备,并且 通常马上就会执行它。(我认为这里的编译就是执行上下文的进入执行上下文(创建)阶段,因为编译往往就在代码执行前进行的。js引擎一般会对代码的执行进行大量的优化工作例如JIT

JavaScript 引擎执行的步骤更为复杂。

作用域

定义如何在某些位置存储变量,以及如何在稍后找到这些变量。我们称这组规则为作用域。是通过标识符名称查询变量的一组规则。作用域是在代码编译阶段确定的,一旦代码写好,它的作用域就确定了。js中只有两种作用域,即全局作用域和局部作用域。

代码一旦写好, 不用执行, 作用范围就已经确定好了。但真正能访问到的的值是什么还需要执行上下文进入创建时候确认,就是把规则转换为具体的对象。

var a = 2解析这段简单的代码的过程是什么样的呢?

编译器先进行词法分析。但是这个编译器不是单单的自己工作,它需要结合作用域一起。

  1. 遇到 var a,编译器 让 作用域 去查看对于这个特定的作用域集合,变量 a 是否已经存在了。如果是,编译器 就忽略这个声明并继续前进。否则,编译器 就让 作用域 去为这个作用域集合声明一个称为 a 的新变量。

  2. 然后 编译器 为 引擎 生成稍后要执行的代码,来处理赋值 a = 2。引擎 运行的代码首先让 作用域 去查看在当前的作用域集合中是否有一个称为 a 的变量可以访问。如果有,引擎 就使用这个变量。如果没有,引擎 就查看 其他地方(参见下面的嵌套 作用域 一节)。

当 引擎 执行 编译器 在第二步为它产生的代码时,它必须查询变量 a 来看它是否已经被声明过了,而且这个查询是咨询 作用域 的。但是 引擎 所实施的查询的类型会影响查询的结果。
在我们这个例子中,引擎 将会对变量 a 实施一个“LHS”查询。另一种类型的查询称为“RHS”。RHS 是难以察觉的,因为它简单地查询某个变量的值,而 LHS 查询是试着找到变量容器本身,以便它可以赋值。

作用域就像大楼一样会有作用域链的嵌套(执行上下文会产生作用域链)。

变量对象

我们首先看一下什么是变量对象
如果变量与执行上下文相关,那变量自己应该知道它的数据存储在哪里,并且知道如何访问。这种机制称为变量对象。
定义几乎和作用域一样,那这两者有什么区别呢?
我的理解为:作用域是一个抽象的概念,变量对象是对抽象概念实现的一个实实在在的对象。上面提到的作用域是一个抽象的概念,js中并没有实际的一个作用域去配合引擎执行代码。只是一套规则。

VO 和 AO

  • VO (Variable Object)变量对象,对应的是函数创建阶段,JS解析引擎进行预解析时,所有变量和函数的声明(即在JS引擎的预解析阶段,就确定了VO的内容,只不过此时大部分属性的值都是undefined)。存储着:
    (1)变量 (var, 变量声明); // 只有通过var声明的才会进入变量对象 a=1 这种不会
    (2)函数声明 (FunctionDeclaration, 缩写为FD);
    (3)函数的形参
  • AO(Activation Object)活动对象,对应的是函数执行阶段,对VO的属性进行赋值。

VO是不可以被访问的,AO是可以被访问的。
AO 实际上是包含了 VO 的。因为除了 VO 之外,AO 还包含函数的 parameters,以及 arguments 这个特殊对象。
AO = VO + function parameters + argumentss

执行上下文

执行上下文可以理解为当前代码的执行环境。是在函数执行时候产生的。以栈的方式,当Javascript解释器初始化执行代码时,它首先默认进入一个全局执行上下文。在此基础上每一次函数的调用都将创建一个新的执行上下文。

每次一个新的执行上下文被创建时,它都被添加到了执行栈的顶部。浏览器总是执行当前位于执行栈顶部的执行上下文。一旦执行完成,它就会被从栈的顶部移除,并将控制权返回到它下面的执行上下文。
如何产生执行上下文

  1. 全局代码
  2. 函数代码
  3. eval代码

可以将每个执行上下文抽象为一个对象并有三个属性。

executionContextObj = {
    scopeChain: { /* 变量对象(variableObject)+ 所有父执行上下文的变量对象*/ },  // 作用域链
    variableObject: { /*函数 arguments/参数,内部变量和函数声明 */ },  // 变量对象
    this: {} 
}

scopeChain:作用域链。函数执行上下文对象产生的作用域链。
那么作用域链是什么呢?函数作用域链 = 活动对象(AO) + scope属性
scope属性是什么呢?
scope属性是静态的,代码写好时候就是确定的,scope为他们外层作用域也就是外层变量(该函数对象的所有父变量对象的)对象(VO)的集合。执行上下文会复制函数 [[scope]] 属性创建作用域链。函数的作用域链,是函数执行的时候动态创建的,但是它又是基于静态词法的环境(scope属性)这就是为什么作用域是静态的,作用域链一般都是动态的原因动静结合

执行上下文一般分为两个阶段

  1. 创建(进入执行上下文)阶段 // 应该是一个很短暂的瞬间,函数被调用但是内部没有执行就为创建阶段
  2. 执行阶段
    如最上面那副图所示

创建阶段(当函数被调用,但未开始执行内部代码之前)

  • 创建 Scope Chain
  • 创建VO/AO (函数内部变量声明、函数声明、函数参数) // 变量提升存在这里
  • 设置this值

激活阶段/代码执行阶段

  • 设置变量的值、函数的引用,然后解释/执行代码。

为什么变量提升存在于执行上下文创建阶段而不是编译阶段?

编译阶段只是把代码生成计算机可识别的代码,计算机真正去理解代码还是需要执行。

执行上下文概念
执行上下文实例
汤姆大叔作用域链(Scope Chain)
了解执行上下文
了解完概念后试着用上下文的概念解释一个问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容