首发地址: https://github.com/jeuino/Blo...
在上一篇《JavaScript 以内存空间》中,简单介绍了下 JavaScript 中的变量是如何存储的。本篇文章将总结一下变量和函数在运行时是如何查找并引用的。git
在《JavaScript 之执行上下文》中,咱们知道了一段代码在开始执行时,首先会建立一个执行上下文。而当进入执行上下文时,就会建立一个变量对象,此时代码还未执行。github
变量对象是与执行上下文相关的数据做用域,执行上下文中定义的全部变量和函数都保存在这个对象中。能够将变量对象理解为做用域这个抽象概念的实体,当代码执行时,是从变量对象中查找是否存在相应的变量的。它具体是如何查找的呢?咱们继续往下看。函数
变量对象的建立,依次经历了如下三个过程:ui
变量对象的建立,是优先扫描函数声明的,若是变量与函数同名,则以函数为主。下面简单解释下缘由:
假设变量对象(做用域)中已经存在一个名为 foo 的属性,它表明一个函数引用。当扫描变量声明时,又遇到一个命名为 foo 的变量,解释器会询问变量对象(做用域)是否已经存在一个该名称的标识符,若是存在,解释器会忽略该指令,继续执行;不然它会要求变量对象声明一个命名为 foo 的属性,并赋值为 undefined。this
因为全局执行上下文和函数执行上下文中的变量对象有一些差别,因此下面对它们分别进行介绍。spa
在全局执行上下文中,变量对象初始化是全局对象,也就是 window 对象。所以全部声明的全局变量和函数都是做为 window 对象的属性和方法建立的。3d
全局对象是预约义的对象,做为 JavaScript 的全局函数和全局属性的占位符。经过使用全局对象,能够访问其余全部预约义的对象、函数和属性。全局对象不是任何对象的属性,因此它没有名称。code
在顶层 JavaScript 代码中,能够用关键字 this 引用全局对象。对象
由于全局对象是做用域链的头,这意味着在顶层 JavaScript 代码中声明的全部变量都将成为全局对象的属性。blog
在函数执行上下文中,变量对象就是其活动对象(activation object, AO)。
什么是活动对象?
变量对象和活动对象实际上是一个对象,二者意思相同,只是处于执行上下文的不一样生命周期。
执行上下文的生命周期包括两个阶段:建立阶段和执行阶段。后续会写一篇文章单独总结。
变量对象就是在建立阶段时初始化的,此时代码还未执行,变量对象中的属性不能被访问。进入执行阶段后,开始逐行执行代码,此时变量对象就会被激活变成活动对象(AO),其各类属性才能被访问。此时就能够经过查找变量对象上是否存在某属性的方式查找声明的变量和函数,获取到引用后进行变量赋值、函数调用等操做。
咱们一块儿来看下下面这段代码生成的变量对象是什么样子的:
function fn(a, b) { var c = 2; function fn1() {} var d = function () {}; } fn(1, 2, 3);
// fn 执行上下文中的变量对象 VO = { Arguments: { 0: 1, 1: 2, 2: 3, length: 3 }, a: 1, b: 2, c: undefined, fn1: <fn1 reference>, d: undefined }
此时的变量对象是在代码执行前建立的,变量对象中的属性都不能访问。在进入执行阶段以后,变量对象变成了活动对象,此时变量对象的属性能够被访问了。而后开始执行代码,代码执行的过程当中可能会修改变量对象的属性值。
仍是上面的例子,当代码执行完毕,这时的 AO 变成:
AO = { Arguments: { 0: 1, 1: 2, 2: 3, length: 3 }, a: 1, b: 2, c: 2, fn1: <fn1 reference>, d: <FunctionExpression "d" reference> }
总结:
在每一个执行上下文中,都包括三个重要的属性:
下篇文章将开始介绍执行上下文中的this
关键字,敬请期待。
参考:
JavaScript深刻之变量对象
JavaScript 之深刻理解执行上下文