zoukankan      html  css  js  c++  java
  • 简单理解js闭包

    什么是闭包?
    我们先来看一段代码:

     function a() {
            var n = 0;
    
            function inc() {
                n++;
                console.log(n);
            }
    
            inc();
            inc();
        }
        a(); //控制台输出1,再输出2 

    再来看一段代码:

      function a() {
            var n = 0;
            this.inc = function () {
                n++;
                console.log(n);
            };
        }
        var c = new a();
        c.inc();  //控制台输出1
      
    c.inc(); //控制台输出2

    什么是闭包?这就是闭包!

    有权访问另一个函数作用域内变量的函数都是闭包。这里 inc 函数访问了构造函数 a 里面的变量 n,所以形成了一个闭包。

    再来看一段代码:

    function a() {
            var n = 0;
    
            function inc() {
                n++;
                console.log(n);
            }
    
            return inc;
        }
        var c = a();
        c();  //控制台输出1
        c();  // 控制台输出2

    看看是怎么执行的:

    var c = a(),这一句 a()返回的是函数 inc,那这句等同于 var c = inc;

    c(),这一句等同于 inc();  注意,函数名只是一个标识(指向函数的指针),而()才是执行函数。

    后面三句翻译过来就是:  var c = inc;  inc();  inc();,跟第一段代码有区别吗? 没有。

    什么是闭包?这就是闭包!

    为啥要这样写?
    我们知道,js的每个函数都是一个个小黑屋,它可以获取外界信息,但是外界却无法直接看到里面的内容。将变量 n 放进小黑屋里,除了 inc 函数之外,没有其他办法能接触到变量 n,而且在函数 a 外定义同名的变量 n 也是互不影响的,这就是所谓的增强“封装性”。

    而之所以要用 return 返回函数标识 inc,是因为在 a 函数外部无法直接调用 inc 函数,所以 return inc 与外部联系起来,代码 2 中的 this 也是将 inc 与外部联系起来而已。

    常见的陷阱

    unction createFunctions() {
            var result = new Array();
            for (var i = 0; i < 10; i++) {
                result[i] = function () {
                    return i;
                };
            }
            return result;
        }
        var funcs = createFunctions();
        for (var i = 0; i < funcs.length; i++) {
            console.log(funcs[i]());
        }

    乍一看,以为输出 0~9 ,万万没想到输出10个10?

    这里的陷阱就是:函数带()才是执行函数! 单纯的一句 var f = function() { alert('Hi'); }; 是不会弹窗的,后面接一句 f(); 才会执行函数内部的代码。上面代码翻译一下就是:

    var result = new Array(), i;
    result[0] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
    result[1] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
    ...
    result[9] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
    i = 10;
    funcs = result;
    result = null;
    
    console.log(i); // funcs[0]()就是执行 return i 语句,就是返回10
    console.log(i); // funcs[1]()就是执行 return i 语句,就是返回10
    ...
    console.log(i); // funcs[9]()就是执行 return i 语句,就是返回10

    为什么只垃圾回收了 result,但却不收了 i 呢? 因为 i 还在被 function 引用着啊。好比一个餐厅,盘子总是有限的,所以服务员会去巡台回收空盘子,但还装着菜的盘子他怎么敢收? 当然,你自己手动倒掉了盘子里面的菜(=null),那盘子就会被收走了,这就是所谓的内存回收机制。

    至于 i 的值怎么还能保留,其实从文章开头一路读下来,这应该没有什么可以纠结的地方。盘子里面的菜,吃了一块不就应该少一块吗?

    总结:

    闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会徒增内存消耗!另外使用闭包也要注意变量的值是否符合你的要求,因为他就像一个静态私有变量一样。闭包通常会跟很多东西混搭起来,接触多了才能加深理解,这里只是开个头说说基础性的东西。

    一切的失败都只因为当事人能力的不足
  • 相关阅读:
    eclipse如何与git 配合工作。
    git托管代码(二)
    PPC2003 安装 CFNET 3.5成功
    我的Window Mobile WCF 項目 第三篇 WM窗体设计
    我的Window Mobile WCF 項目 第一篇Mobile开发和WinForm开发的区别
    我的Window Mobile WCF 項目 第七天
    我的Window Mobile WCF 項目 第二篇 WindowsMobile访问WCF
    WCF 用vs2010 和 vs2008的简单对比测试
    vs2010beta1 和 搜狗输入法 冲突,按下 Ctrl 键就报错,重装搜狗解决
    我的Window Mobile WCF 項目 第六天 (二)
  • 原文地址:https://www.cnblogs.com/kakutian/p/7082950.html
Copyright © 2011-2022 走看看