JavaScript高级编程学习2——执行环境

        首先来看下两段代码。

代码1:

//代码1:
var firstVar = 'wuxq';
function A() {
firstVar
= 'wuxiaoqian';
alert(firstVar);
//输出wuxiaoqian
}
A();
alert(firstVar);
//输出wuxiaoqian

代码2:

//代码2:
var firstVar = 'wuxq';
function A() {
var firstVar = 'wuxiaoqian';
alert(firstVar);
//输出wuxiaoqian
}
A();
alert(firstVar);
//输出wuxq

      在C语言中,我们存在全局作用域,函数作用域,块作用域。如果上面对代码在C语言中是会出错的,因为在函数里面声明一个和全局变量一致的局部变量。但是在ECMA-Script里面不会。在ECMAScript里面我们可以这样实现,函数里面的局部变量会覆盖全局变量。对于C语言来说,存在着快作用域。但是在ECMAScript里面是没有的。下面的这段代码是没有错误的。输出的sum是2.

function A() {
var firstVar = 'wuxiaoqian';
for (var i = 0; i < 3; i++) {
var sum = i;
}
alert(sum);
alert(firstVar);
//输出wuxiaoqian
}

      因此可以得出结论:ECMAScript中的作用域分为全局作用域和函数作用域,定义在任何函数外部的变量是全局作用域变量,不使用“var”关键字定义在函数内部的变量也是全局作用域变量,只有使用“var”关键字定义在函数内部的变量才是函数作用域变量,函数作用域变量会覆盖同名的全局作用域变量。全局作用域变量的可见区域是整个脚本(除了被同名函数作用域变量覆盖的区域),函数作用域变量的可见区域是函数内部(除了被内部嵌套函数中同名函数作用域变量覆盖的区域)。

当ECMAScript开始执行时,创建一个全局执行环境;每次进入一个函数时(这个函数被调用),则创建一个当前函数的执行环境并压入栈,离开此函数时从栈中弹出此执行环境并销毁。

      原理介绍:在JavaScript中,当进入可执行代码的时候,会创建一个逻辑上的栈执行环境,而目前执行的逻辑代码总是在栈顶,也就是说当开始执行JavaScript的时候,会创建一个全局的执行环境。当进入一个调用的函数的时候,会创建这个函数的执行环境并且将其压入栈顶。当运行完毕后,将函数的执行环境弹出。回到全局的执行环境。每一个执行环境都会有一个与其对象的变量对象,这个变量中记录着此执行环境定义的函数和变量。

代码:

var name = "Microsoft";  
function funcA(){  
    var name = "Google";  
    alert(name);  
}  
funcA(); //Google  
alert(name); //Microsoft 

执行环境图:

 

      对于其中的this指的是触发此执行环境的对象,也就是调用func的对象。在这里FuncA是在全局环境下进行调用。因此这里的this是window。而argument是函数的参数对象。

      作用域链:

      对于代码1和代码2分别输出不同的变量。但是ECMAScript是如何实现对局部变量和全局变量的区分的呢?这里就引入的作用域链,也就是每个执行环境都会有一个执行链。执行链形象点可以把其想象成指针栈。栈中的每个指针指向当前执行环境的变量。而且这个指针栈也是有排列顺序的,从栈顶到栈底依次指向当前执行环境,上一级执行环境,接下来在上上级,这也就意味着在创建执行环境的同时会创建指针栈。而且在创建指针栈的同时会将上一级执行环境中的指针栈复制过来,因为这样才能访问到上一级执行环境的变量。在离开函数的时候,当弹出执行环境的栈顶,销毁执行环境,执行环境的变量和作用链域。

      再补充一点:在从上一级复制执行链后,会将本执行环境中新的变量压入栈顶,而执行环境在搜索变量是从栈顶向栈底搜索的,这也就是为什么函数局部变量能覆盖全局变量的原因。

参考文章:http://www.cnblogs.com/leoo2sk/archive/2010/12/19/ecmascript-scope.html


posted @ 2011-03-14 11:42  雁北飞  阅读(230)  评论(0编辑  收藏  举报