JavaScript 闭包的例子

例子出自<<JavaScript权威指南>>, 加上个人的理解和总结, 欢迎交流!

/*****************************************************************************/
/* 将一个立即调用函数的返回值赋给变量uniqueInteger
 * 特点: 内部函数可以访问外部函数中的局部变量,当外部匿名函数立即调用返回之后, 除了返回的函数对象外
 * 其他任何代码都无法访问私有变量counter, 实现了变量的隔离(相当于命名空间).
 */
var uniqueInteger = (function(){
    var counter = 0;
    return function(){
        return counter++;
    };
}());
/*****************************************************************************/

/*****************************************************************************/
/* 多个嵌套函数共享一个私有变量
 */
function counter(){
    var n = 0;
    return {
        count: function(){
            return n++;
        },
        reset: function(){
            n = 0;
        }
    };
}
var c = counter(); // 相当于上一个例子中的立即调用, 只是得到的是一个直接对象, 而不是函数对象
var d = counter(); // 定义了另一个对象. 和c各自独立.
// 两个对象各自维护自己的私有变量 n , 其他外部代码不能再直接访问它们的 n 的值.
console.log(c.count()); //0
console.log(c.count()); //1
c.reset();
console.log(c.count()); //0
d.count(); d.reset();
//上面的counter()也可以类似如下实现, 因为参数和局部变量一样保存在作用域链中.
function counter2(n){
    n = n || 0;
    return {
        get count(){return n++;},
        set count(m){
            if(m >= n) n = m;
            else throw Error("count can only be set to a larger value");
        }
    };
}
var e = counter2(10);
e.count;
console.log(e.count); // 11
e.count = 20; 
console.log(e.count); // 20
console.log(e.count); // 21
/*****************************************************************************/

/*****************************************************************************/
/* 利用闭包实现私有属性存取器方法
 * 为传入的某个对象加入setter和getter方法, 但是setter/getter方法操作的属性并没有添加到
 * 对象 o 中, 而是由闭包代为保管!
 * 这样只能通过setter/getter进行访问, 其他地方无法直接访问,成为私有变量.
 */
function addPrivateProperty(o,name,predicate){
    var value;
    o['get'+name] = function(){
        return value;
    },
    o['set'+name] = function(v){
        if(predicate && !predicate(v))
            throw Error("set"+name+":invalid value "+v);
        else
            value = v;
    };
}
var o = {};
addPrivateProperty(o,"Name",function(x){return typeof(x) == "string";});
o.setName("roger");
console.log(o.getName()); // roger
/*****************************************************************************/

/*****************************************************************************/
/* 当多个闭包共享同样的私有变量或变量时要注意作用域时动态变化的.
 * 嵌套的函数不会讲作用域内的私有成员复制一份(只是引用), 也不会对所绑定的变量生成静态快照.
 */
function constfunc(v){
    return function(){
        return v;
    };
}
var funcs = [];
for(var i=0;i<10;++i){
    // 创建多个闭包共享变量 i.作用域链在变化,直到循环结束, 但是执行constfunc时保存了i的状态.
    funcs[i] = constfunc(i); 
}
console.log(funcs[5]()); // 5
function constfunc2(){
    var funcs = [];
    for(var i=0;i<10;++i){
        //函数对象并没有保存i的状态, 在外面调用时作用域的状态已经变化了, 和预期不一样.
        //因为内嵌对象不会将作用域内的私有成员复制一份(只是一份引用而已)
        funcs[i] = function(){
            return i;
        };
    }
    return funcs;
}
var funcs = constfunc2();
console.log(funcs[5]()); //10
function constfunc3(){
    var funcs = [];
    for(var i=0;i<10;++i){
        funcs[i] = (function(){
            return i;
        }()); //使用函数立即调用, 直接将闭包的状态保存在了funcs[i]中.
    }
    return funcs;
}
var funcs = constfunc3();
console.log(funcs[5]); // 5
/*****************************************************************************/

/*****************************************************************************/
/*需要注意this和arguments
 1. this不是变量, 而是关键字, 会随着作用域而变化
 2. arguments是函数在调用时引擎自动创建的变量, 也是随作用域而变化的
 解决方法: 将外部函数的this和arguments的内容(而不是引用)保存到局部变量中, 
 从而避免作用域变化带来的不确定性
*/
原文地址:https://www.cnblogs.com/roger9567/p/5042190.html