javascript最难理解之闭包

个人感觉JS中最难理解的几个概念中就有闭包,本文记录一下自己学习闭包的笔记。

一、变量的作用域

理解闭包的基础是变量作用域, JS中变量的就两种:全局变量和局部变量

1.1、函数内部可以直接读取全局变量

var global = "this is a global variable";
function glo(){
    alert(global);
}
glo(); //弹出 this is a global variable

1.2、在函数外部无法读取函数内的局部变量

function loc(){
    var local = "this is a local variable";
}
alert(local); //报错 local is not defined
注意:声明变量时一定要使用var关键字。如果不用的话,实际上声明了一个全局变量!

二、函数外部如何读取函数内的局部变量

上文已经说过,函数外部无法读取函数内的局部变量,但有时候又必须这样去做,那么该如何实现呢?
常用的一种方法是:在function里嵌套function,内部的function可以访问外部function里的变量,如下代码:
console.log("********代码一*************")
function outer(){
    var n=0;
    function inner(){
        n++; //内部函数访问外部函数outer里的变量n
        console.log(n)
    }
    inner();
    inner();
}
outer();    //控制台先输出1,再输出2

链式作用域:函数inner被包括在函数outer内部,这时outer内部的所有局部变量,对inner都是可见的。但是反过来就不行,inner内部的局部变量,对outer就是不可见的。这就是Javascript语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

在函数外部读取它的内部变量:既然inner可以读取outer中的局部变量,那么只要把inner作为返回值,不就可以在outer外部读取它的内部变量了!

console.log("********代码二*************")
function outer(){
    var n=0;
    function inner(){
        n++; //访问外部函数outter的变量n
        console.log(n)
    }
    return inner;  //将内部函数作为返回值
}
var result = outer(); //outer()返回的是函数inner
                      //这句等同于 var result = inner;
result();  //控制台输出1; 
result();  //控制台输出2; 
//这句等同于执行 inner() ; 也就实现了在outer函数外部访问其内的局部变量n
//所以最后这三句翻译过来就是:  
//var result = inner;  
//inner(); 
//inner();,
//与代码一完全相同

函数名只是一个标识(指向函数的指针),而()才是执行函数。
代码一与代码二效果完全相同

三、什么是闭包

代码二中的inner函数就是闭包

闭包就是能够读取其他函数内部变量的函数。 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数“。

闭包的概念:function里嵌套function,内部的function可以访问外部function里的变量,这不是闭包(如代码一);只有当外部函数return的是内部function时,才是一个闭包(如代码二)。内部function会close-over外部function的变量直到内部function结束

三、闭包的常见用法

闭包的最大用处有两个:一个是前面提到的可以读取函数内部的变量;另一个就是让这些变量的值始终保持在内存中。

闭包常用于创建含有隐藏数据的函数,如下代码

var db = (function() {
        var data = {};
        // 创建一个隐藏的对象data, 这个对象持有一些数据
        // 从外部是不能访问data这个对象
        // 创建一个函数, 这个函数提供一些访问data对象的数据的方法
        return function(key, val) { //闭包
            if (val === undefined) { return data[key] } // get
            else { return data[key] = val } // set
            }
        // 我们可以调用这个匿名方法
        // 返回这个内部函数,它是一个闭包
 })();
        db('x'); // 返回 undefined
        db('x', 1); // 设置data['x']为1
        db('x'); // 返回 1
        // 我们不可能访问data这个对象本身
        // 但是我们可以设置它的成员

四、总结

闭包的概念:function里嵌套function,内部的function访问外部function里的变量,并且外部函数return的是内部function,这个内部函数就是闭包,如下代码:

function a(){
    var n = 0;
    function b(){
        n++;
    }
    return b;
}

五、注意事项

1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

六、参考资源

http://www.cnblogs.com/qieguo/p/5457040.html
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值