javascript的词法作用域

这个概念是js中相当基础也是极为重要的,很多想当然的错误或感觉怪异的问题都是和这个东西有关。所以,本文主要说下这个名词的概念以及讨论下他牵扯出来的有关变量、函数、闭包的问题。

  1. 由变量开始谈
      习惯性先来段代码:
var x = "globol value";
    var getValue = function(){
        alert(x);    //弹出"undefined"
        var x = "local value";
        alert(x);    //弹出"local value";
    }
    getValue();

其实理解这个问题的关键就是要清楚x的作用域。
  第一个var x中的x是全局变量,说到这里顺带说下,js解释器在执行任何代码之前会先创建一个全局对象(global object),全局变量就是相当于这个全局对象的一个属性。同理,对于getValue这个函数,就会生成一个叫做调用对象的东西,局部变量就是这个调用对象的属性,例子中第二个var x中的x就是局部变量。
要理解的话,其实我们可以对比传统面向对象的(如JAVA、C#)中的变量的作用域,我们知道C#中的变量作用域是块级的,即这个变量只能活动在定义他的一个直接外界内,如if子句内,for子句内定义的变量外界是无法读取的。而js中呢,变量却不是这样的,在同一个函数内定义的变量其它的成员是可以访问的。看个例子会清楚很多:

function test(o){
        var i = 0;
        if(typeof o == "object"){
            var j = 0;                    
            for(var k=0; k < 10; k++){
                document.write(k);
            }
            document.write(k);            //k是可以被访问到的,即使他在for子句内
        }
        document.write(j);                //说明j是可以被访问到的,即使他在if子句内
    }

  当定义了一个函数后,当前的作用域就会被保存下来,并且成为函数内部状态的一部分,这个是很重要的一个概念。下面我们回到开篇的那个例子,当getValue函数被定义的时候,他的作用域被保存起来,还有被加到作用域链上,他的上端就是全局执行环境。当调用getValue方法的时候,js解释器首先会把作用域设置为定义函数的时候的那个作用域(即之前保存那个),接下来,他在作用域的前加上调用对象即getValue这个函数,再在他的上端加上全局对象。
2. 深入探索
  这个作用域链其实和原型链有点相似,也好似在很作用域内找不到就会向上去找。比方说开篇那个例子,找x的时候,(对了这里要先介绍下js的预定义机制,就是js解释器会先对var定义的变量进行初始化,应该说只是起了定义的作用当没赋值),会先在本作用域内找,有预定义知可以找到x,但是没赋值,所以是undefined值。知道了这点我们来知道开篇那个代码其实是等价于下面这个的:

var x = "globol value";
    var getValue = function(){
        var x;
        alert(x);    //弹出"undefined"
        x = "local value";
        alert(x);    //弹出"local value";
    }
    getValue();

  楚了以上关于词法作用域的概念后,我们就不难理解闭包的概念了,他只是用到了作用域链的不可向下性(我取的名词..),即下面的作用域可以访问上面的,但上面的不可以访问下面的。当然这只是构成闭包的一个条件,闭包更重要的还是外部函数持有内部函数的一个嵌套函数的引用,由于闭包不是本文主要要讨论的(ps:谈封装的时候会说到),所以只是简单看下例子:

function foo(){
        var age = 10;
        function boo(){
                age += 10;
                return age;
        }
        return boo;
    }
    
    var tx = new foo();
    alert(tx());    //20
posted @ 2017-07-25 09:43  小飞雪  阅读(409)  评论(0编辑  收藏  举报