代码改变世界

Javascript执行环境与作用域

2012-04-21 17:59  Wid纬度  阅读(1544)  评论(2编辑  收藏  举报

 

 ü  定义

  执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中,

虽然我们编写的代码无法访问这个对象,但是解析器在处理数据的时候会在后台使用它

 

ü  全局执行环境

  全局执行环境是最外层的一个执行环境,根据实现所在的执行环境不同,表示执行环境的对象也不一样,在Web浏览器中,我们认为window对象就是全局执行环境,所有的变量及函数都是作为执行环境的属性或方法添加的

 

ü 

  每个函数在被调用的时候都会创建自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境

 

ü  作用域链

   当代码在一个环境中执行时,会创建由变量对象构成的一个作用域链,作用域链用是保证对执行环境的有权访问的所有变量和函数的有序访问。作用域链由当前执行的代码所在环境的变量对象,下一个变量对象同包含它的外部环境构成,再下一个变量对象则由包含下一个变量的外部环境构成。这样一直延续到全局执行环境

 

ü  标识符解析过程总是沿着作用域一级一级的向上搜索标识符

  示例:

        var outerVariable = "outer";

        function funcVariable() {
            var innerVariable = "inner";
        }

  对于funcVariable函数来讲,它的作用域链就包括两个对象,一个是自己的变量对象,另一个则是外部的全局变量对象,对于funcVariable函数来讲可以访问到变量outerVariable是因为可以在作用域链上找到该变量

我们可以从上得出结论,内部环境可以通过作用域链访问所有的外部环境,而外部环境是不能访问内部环境中的任何变量和函数的

  下面通过几个示例来分析一下javascript作用域相关内容

例1:

     var name = "windowScope";
        var func = function () {
            var name = "function1";
            var func1Var = "function1_Variable";

            (function () {
                var name = "function2";
                var func2Var = "functioin2_Variable";

                alert("可以访问自身name、func1Var、func2Var、但是不能访问func3Var");

                (function () {
                    var name = "function3";
                    var func3Var = "functioin2_Variable";

                    alert(name); //不会得到"function2",因为在自身作用域中已存在
                       alert("可以访问自身name、func1Var、func2Var、func3Var");
                })();
})(); }; func();

例2:

     var func1 = function () {
            var func2Var = "function1";

            function function2() {
                var func2Var = "function2";

                inFunc2Var = " belong to function2 ?"; // 未用var声明,只要函数function2被调用,变量马上就变成全局变量
            }

            function2();
            alert(inFunc2Var);//no belong to function2
        }
        func1();
        alert(inFunc2Var);// 可以访问到变量inFunc2Var

例3:

     var variable = "outer";
        function funcVariable() {

            alert(variable);// undefined
            var variable = "inner";
            alert(variable)// inner
        }
        funcVariable();

  上面也看了一些例子,下面来讲一讲作用域链是怎么样创建的 

ü  作用域链是如何创建的?

1.       当函数定义时,会将它定义时刻的作用域链(函数定义外部的作用域链)链接到函数对象的内部属性[[Scope]].

2.       当某一个函数被调用时,会创建一个执行环境及相应的作用域链,并把作用域链赋值给一个特殊的内部属性[[Scope]],然后使用this,arguments和其它命名参数的值来初始化函数的活动对象(activation object).

 

这样描述也不太直观,下面来参考一个例子讲解下作用域链是如何创建的

     var variable = "outer";
        function funcVariable() {
            var variable = "inner";
        }

 

  当如上函数被定义后,会创建一个预先包含全局变量对象的作用域链,并将这个作用域链保存在[[Scope]]

 

 

 

当调用函数funcVariable(),会为函数创建一个执行环境,此后会创建一个活动对象并被推入执行环境作用域链的前端如下图

 

 

 

 

  所以对于funcVariable来讲,其作用域链中包含了两个变量对象,一个是全局的一个是本地的.显然作用域链本质上是一个指向变量对象的指针列表,一般来讲当函数执行完毕后,局部活动对象就会被销毁,仅保存全局的作用域.另外当进行变量搜索的时候就会按照作用域链向上搜索,直到找到变量为止,没找到就会报错.

 

小结:

Javascript与其它语言差不多,在每次调用一个函数后,就进入函数的作用域,当离开函数的时候就返回调用前的作用域,

 

快结束了,再来看个问题,如上例3中代码,为什么第一次弹出为undefined,如下

 

     var variable = "outer";
        function funcVariable() {

            alert(variable);// undefined
            var variable = "inner";
            alert(variable)// inner
        }
        funcVariable();

 

 

Javascript特性: var变量和function定义做预解析"

让我们来分析一下为什么第一个弹出来的是”undefined”,当运行以上代码时,javascript预解析功能便得知函数存在变量variable,而此时变量的值是undefined,以上代码相当于

 

        var variable = "outer";
        function funcVariable() {
            var variable;
            alert(variable);// undefined
            variable = "inner";
            alert(variable)// inner
        }
        funcVariable();

而在第二句调用alert函数时就发生了标识符搜索的过程,所以此时本地的活动对象中变量variable的值还是undefined,但是经过下一句赋值后,活动对象中的变量值就被修改为”inner”,再次访问就不会有问题.

 

注:文中有一段中讲到"一般来讲",那在什么时候又不满足情况了?这个就由接下来的文章解答吧!