JavaScript的作用域和闭包

对于初学者而言,可以这样理解: JS只有两种作用域

1. 全局作用域

2. 函数作用域 

必须牢记一点 JS中没有块级作用域

{
    var test=10;
}
console.log(test);    // 控制台输出:10

再看一个

var obj={
    test:10,
    myFunc:function(){
        console.log(test); 
    }
};
obj.myfunc();   // 出错,或者IDE直接报警了

这个就更难理解了吧

 写在函数体内的变量,只要不是嵌套在更深层的函数里,就是处在同一作用域的,“互相可见”;而其他的花括号,不管是for后跟的,if后跟的,还是对象字面量的,一概“不作数”,起不到定义作用域的效果,变量声明写在那些花括号的里面或外面都一样。

那位于嵌套的函数里的作用域呢?它们享有“单向透明”的特权,即:在较内层次的作用域内可以访问较外层次作用域里的变量,反之则不行。

function outerFunc(){
    for(var i=0;i<10;i++){doSomething;}
    console.log(i); // 控制台输出10,因为i位于outerFunc的作用域
    var outer = 10;
    function innerFunc(){
        var inner = outer; // 内层作用域可以访问外层作用域里的变量
    }
    console.log(inner); // 报错,外层作用域访问不到内层作用域里的变量
}

再来分析上一个例子。我们试图在myFunc的作用域内部访问test,然而test并不是一个“与myFunc位于同一个对象作用域”的变量,事实上根本不存在“对象作用域”这回事,test是obj的一个属性,不是一个“独立”的变量,要访问test只能通过点运算符obj.test或obj["test"],哪怕是在myFunc内部。当然,myFunc内部可以访问到obj这个位于外层作用域的变量,没有问题。于是将代码改写如下:

var obj={
    test:10,
    myFunc:function(){
        console.log(obj.test); 
    }
};
obj.myfunc();   // 10

既然在内层作用域里可以访问外层作用域,那么就产生了一个有趣的现象,叫做“闭包”。制造一个闭包只需要两步:

1.在内层函数里引用外层函数的变量

2.将内层函数作为外层函数的返回值返回出去

function outer(){
    var test = 10;
    var inner = function(){
        console.log(test++);
    };
    return inner;
}

var myFunc = outer(); // 将outer的返回值(inner函数)赋给myFunc
myFunc(); // 10
myFunc(); // 11
myFunc(); // 12

这个被返回的inner函数就是一个闭包。虽然outer函数运行结束了,但它的内部变量test因为被闭包引用,所以并没有被销毁,而是被保存了起来,并且可以通过闭包继续操作。当然,外界永远无法访问test这个变量,它成了inner(以及myFunc)所指向的函数的“私有变量”。

本文转载自 http://www.cnblogs.com/leegent/p/5377177.html

 

在ES6中新增加了块级作用域( {.....} ), 通过使用let关键字,能够让你声明的变量属于一个单独的代码块:

function foo() {
    
         var a = 1;

          if(a >= 1) {

            let b = 2;

            while (b < 5) {

              let c = b * 2;
              b ++;

              console.log(a + c); 

 
             }


           }
}

foo();

由于使用let代替了var, b只属于if语句,而不是整个foo()的函数作用域. 同样, c也只属于while循环. 

 

posted on 2018-03-02 06:57  新西兰程序员  阅读(107)  评论(0编辑  收藏  举报