closure

Closure:

         JavaScript词缀作用域。javascript的函数在执行时是按照定义作用域链起作用。内嵌函数f()被包含在一个作用域链中,在这个作用域链中scope被赋值为"local scope"。无论f最终在哪里被执行,这种绑定一直存在。

 

var scope = "global scope";

function checkscope() {

    var scope = "local scope";

    function f() {

        return scope;

    }

    return f;

}

console.log(checkscope()())

 

Define your own properties

         函数是一种特殊的object类型,因此也可以有自己属性。

        

 1  // Initialize the counter property of the function object
 2 
 3          //Function decaralation are hoisted so we really can do this assignment before the function declaration
 4 
 5          uniqueInteger.counter = 0;
 6 
 7          //This function returns an unique integer each time when it is called.
 8 
 9          //It uses a property of itself to remember the next value to be returned
10 
11          function uniqueInteger() {
12 
13              return uniqueInteger.counter++;
14 
15          }

 

         但是更安全的做法是使用闭包:

                 

         下面有个更像对象编程的:函数每一次被调用都产生了新的作用域链,并且其私有变量也是独立的。

        

 1 function counter() {
 2 
 3     var n = 0;
 4 
 5     return {count:function () {
 6 
 7         return n++;
 8 
 9     }, reset:function () {
10 
11         n = 0;
12 
13     }};
14 
15 }
16 
17 var c = counter(), d = counter();
18 
19 console.log("c.count(): " + c.count());     //0
20 
21 console.log("d.count(): " + d.count());     //0 c 和 d的count是独立的
22 
23 console.log("c.reset(): " + c.reset());     //reset()和count()共享状态
24 
25 console.log("c.count(): " + c.count());     //0 因为刚把creset()了
26 
27 console.log("d.count(): " + d.count());     //1 d不受影响

 

注意:以上我们见识了在同一个作用域链定义的闭包,会分享外层函数的私有成员。这是一个非常重要的技术,但是有时候闭包不应该共享变量如下:内嵌函数并拷贝作用域或者保留变量的静态快照。对于内嵌函数而言,i是共享的,并且是动态的。

 

 1 // This function returns a function that always returns v [这个不是在for循环内定义闭包,而是提前定义,在循环内被调用,每次调用就产生作用域链]
 2 
 3 function constfunc(v) { return function() { return v; }; }          
 4 
 5 // Create an array of constant functions:
 6 
 7 var funcs = [];
 8 
 9 for(var i = 0; i < 10; i++) funcs[i] = constfunc(i);
10 
11 // The function at array element 5 returns the value 5.
12 
13 funcs[5]() // => 5

 

 

并不同于如下

 1 // Return an array of functions that return the values 0-9
 2 
 3 function constfuncs() {
 4 
 5     var funcs = [];
 6 
 7     for(var i = 0; i < 10; i++)
 8 
 9         funcs[i] = function() { return i; }; //[在for循环内定义了10个闭包,且都只是在一次constfuncs函数的一次调用中完成,而他们都引用i,因此他们分享同一个i的状态。]
10 
11     return funcs;
12 
13 }
14 
15 var funcs = constfuncs();
16 
17 console.log(funcs[5]()) // What does this return? 返回10,且所有的都返回10

 

多重闭包:上面的问题我们可以通过多重闭包来解决

 

 1 /* 使用匿名函数来激发出 创建多重闭包函数所需要的 作用域 */
 2 
 3 function constfuncs() {
 4 
 5     var funcs = [];
 6 
 7     for(var i = 0; i < 10; i++)              {
 8 
 9                    //! funcs[i] = function() { return i; };
10 
11         //使用自执行的匿名函数来激发出作用域
12 
13         (function(){
14 
15             var v=i;    // 记住在这个作用域内的值,这句必须有,值的复制
16 
17             funcs[i]=function(){    //这个下标既可用i也可以用v,因为这个声明语句是被执行了的
18 
19                 console.log(i+" "+v);    // i都等于10
20 
21                 return v;           //在这个内层函数里,必须使用外层无法改变其值的本地变量v,如果使用i那么以在本函数执行时的i值为准;
22 
23             }
24 
25                             //!funcs[i]=function(){return i;}        //回调函数内不可使用i,如果使用i,返回的匿名的i值随着循环的变化。实际上使用了外层可改变值的i
26 
27         }());
28 
29          }
30 
31     return funcs;
32 
33 }

 

中间的那一部分也可以写成如下,这样就更容易理解了:

                  

 1  funcs[i] = (function () {
 2 
 3             var v = i;    // 记住在这个作用域内的值,这句必须有,值的复制
 4 
 5             return  function () {    //这个下标既可用i也可以用v
 6 
 7                 console.log(i + " " + v);    // i都等于10
 8 
 9                 return v;           //在这个内层函数里,必须使用本地变量v
10 
11             }
12 
13             //!funcs[i]=function(){return i;}        //回调函数内不可使用i
14 
15         }());
16 
17                   

 

 或者:

               


    funcs[i] = (function (v) {    //通过匿名函数传入i值,省去显示声明v,这个v是匿名函数的本地变量,外层函数无访问权限,无法改变

                            return  function () {    //这个下标既可用i也可以用v

                                 return v;           //在这个内层函数里,必须使用v;

                                }

                        }(i));

 

 

                   或者还可以写作:

                  

 1  funcs[i]  =  new function () {
 2 
 3                 var v = i;    // 记住在这个作用域内的值,这句必须有,值的复制
 4 
 5                 return   function () {    //这个下标既可用i也可以用v
 6 
 7                     console.log(i + " " + v);    // i都等于10
 8 
 9                     return v;           //在这个内层函数里,必须使用v;
10 
11                 }
12 
13                 //!funcs[i]=function(){return i;}        //回调函数内不可使用i
14 
15          }();

 

                  

注意:内嵌函数不能直接访问外部函数的this,arguments。如果需要,必须在外部函数范围定义一个变量来保证内嵌函数能正确访问。

1 var self = this; // Save this value in a variable for use by nested funcs.
2 
3 var outerArguments = arguments; // Save for use by nested functions

 

posted @ 2013-08-11 21:18  eyotata  阅读(314)  评论(0编辑  收藏  举报