标签:
执行环境(execution context)是JavaScript最为重要的一个概念,执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每一个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。
全局执行环境是最外围的一个执行环境。在Web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。
每个函数都有自己的执行环境。那么每个函数在执行时也就有与之关联的变量对象,对函数来说,也叫活动对象。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途就是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果当前执行环境是函数,那就是变量对象就是函数的活动对象。活动对象在一开始只包含一个变量,arguments对象,这个在介绍函数的时候说过。作用链域的下一个变量对象来自包含它的外部环境,而下一个变量对象则来自下一个包含环境。这样,一直延续一、到全局执行环境。全局执行环境的变量对象window始终是作用链域中的最后一个对象。
在分析具体例子前,先看一下JavaScript的运行顺序。
如果一个文档流中包含多个script代码段(用script标签分隔的js代码或引入的js文件),它们的运行顺序是:
步骤1. 读入第一个代码段(js执行引擎并非一行一行地执行程序,而是一段一段地分析执行的)
步骤2. 做语法分析,有错则报语法错误(比如括号不匹配等),并跳转到步骤5
步骤3. 对var变量和function定义做“预解析”(永远不会报错的,因为只解析正确的声明)
步骤4. 执行代码段,有错则报错(比如变量未定义)
步骤5. 如果还有下一个代码段,则读入下一个代码段,重复步骤2
步骤6. 结束。
着重说明一下上面红色部分。JavaScript标识符的解析是沿着作用域一级一级地搜索标识符的过程。搜索过程始终从作用域的前端开始,也就是从当前执行的代码所在的环境开始,然后逐级地向后(或者说成向上)回朔,直到找到标识为止,如果找不到通常会发送错误。
var arg = 1; function test(){ alert(arg); //100 //var arg = 1; } arg = 100; test();上面例子中,当在test函数的当前作用域中没有找到arg标识符时,就会沿着作用域链到上层作用域中,在上层作用域中我们找到了arg变量,在test函数被调用前,arg变量被赋值为100,所以我alert(arg)会打出100。但如果我们把test函数中注释那行解除注释,那么情况就变了。
var arg = 1; function test(){ alert(arg); //undefined var arg = 1; } arg = 100; test();此时我们的alert(arg)显示的是undefined,这是因为arg变量被定义在了test函数中当前作用域中,我们执行test函数时在当前作用域中找到了这个变量,那么我们就不会沿着作用域链往上找了。但是在这里,arg变量被定义在了alert方法后面,所以执行alert方法时,用的是arg的默认值,也就是undefined。上面这段代码也就等价于:
var arg = 1; function test(){ var arg; alert(arg); //undefined arg = 1; } arg = 100; test();
标签:
原文地址:http://blog.csdn.net/zhuyunhe/article/details/45579285