变量对象
我们先看这样一个例子:
var a = 'Hello';
(function(){
alert(a); //输出结果为undefined
var a = 'World';
})();
为什么a未定义实际上就是因为JavaScript的变量提升特性。这段代码实际上可以看作是这样:
var a = 'Hello';
(function(){
var a;
alert(a); //输出结果为undefined
a = 'World';
})();
这就好理解了。但是为什么会存在这样一种特性呢?我们就必须从JS中查找变量和函数的机制——变量对象说起。
执行上下文
说到变量的使用和函数的执行之前,一定离不开它们作用的环境。每种代码的执行都要依赖于自身的上下文,也就是执行上下文环境。所有的JavaScript程序执行,都可以看作是一个执行上下文堆栈。
当程序开始时,先进入全局执行上下文环境,该环境可以激活另外的函数执行上下文环境,就相当于一个函数调用了其他的函数。激活者被称为caller,被激活者被称为callee。当callee激活时,caller就会暂停自身的执行,将callee的执行上下文push进堆栈并执行,执行结束后pop出再继续执行callee。反复循环直至达到堆栈底部,程序就结束运行。 每个执行上下文可以抽象理解为一个object。该object中有3个基本属性:变量对象,this指针,作用域链。我们今天谈到的变量对象就是存在于执行上下文中的数据作用域,它用于存储被定义在上下文中的变量和函数声明。变量对象的行为与执行上下文的处理流程紧密相关。
执行上下文的代码被分成两个部分处理。
1.进入执行上下文
当进入执行上下文时,变量对象中将创建下列属性:
- 函数的所有形参(在函数上下文中时) 名称和对应值组成。如果没有传递对应值,则为undefined。
- 函数声明 名称和对应值组成。如果变量对象中已存在相同名称属性则替换之。
- 变量声明 名称和对应为undefined的值组成。如果变量名称已存在也不会替换已存在属性。
2.执行代码
在该阶段将按照顺序执行代码并给上一阶段定义的变量赋值。
不同执行上下文中的变量对象区别
先看一个例子。
alert(a); //undefined
alert(b); //"b"没有声明
var a = 1;
b = 2;
按过去的经验来看,b应该是一个全局变量,但其实b是全局对象的属性。变量只能通过var关键字才能声明(ES6中增加了其他关键字)。b=2实际上相当于global.b=2。引起混淆的原因正是因为不同执行上下文中的变量对象差别导致的。
1.全局上下文中的变量对象
在其他作用域中是不能直接访问变量对象的,只有全局上下文中的变量对象允许通过属性名称直接访问其中的属性。因为全局上下文中的变量对象就是全局对象。
全局对象是在进入程序之前就创建了的对象,创建时就有一系列初始化属性,格式如下。
global = {
Math:```,
String:```,
Object:```,
window: global
}
通过var关键字或函数声明定义的数据将作为变量对象的一部分加入进global对象,不使用var关键字时将作为global的属性加入进global对象。
2.函数上下文中的变量对象
变量对象不能直接被访问,当进入函数上下文时将基于arguments属性创建一个活动对象。argument属性值为对象,包括callee(当前函数),length(实参数量),properties-index(函数实际参数)。再按照进入上下文时的步骤补充活动对象。
-- EOF --
前端开发
」下,并被添加
「JavaScript」
标签。