zoukankan      html  css  js  c++  java
  • JavaScript的闭包

    1. 什么是闭包
    通俗地讲,JavaScript 中每个的函数都是一个闭包,但通常意义上嵌套的函数更能够体现出闭包的特性,请看下面这个例子:
    var generateClosure = function() {
    var count = 0;
    var get = function() {
    count ++;
    return count;
    };
    return get;
    };
    var counter = generateClosure();
    console.log(counter()); // 输出 1
    console.log(counter()); // 输出 2
    console.log(counter()); // 输出 3

    现象:

    这段代码中,generateClosure() 函数中有一个局部变量count,初值为 0。
    还有一个叫做 get 的函数,get 将其父作用域,也就是 generateClosure() 函数中的 count 变量增加 1,并返回 count 的值。generateClosure() 的返回值是 get 函数。
    在外部我们通过 counter 变量调用了 generateClosure() 函数并获取了它的返回值,也就是 get 函数,接下来反复调用几次 counter(),我们发现每次返回的值都递增了 1。
     
    分析:
    让我们看看上面的例子有什么特点,按照通常命令式编程思维的理解,count 是generateClosure 函数内部的变量,它的生命周期就是 generateClosure 被调用的时期,当 generateClosure 从调用栈中返回时,count 变量申请的空间也就被释放。
    问题是,在 generateClosure() 调用结束后,counter() 却引用了“已经释放了的” count变量,而且非但没有出错,反而每次调用 counter() 时还修改并返回了 count。
    这是怎么回事呢?
    这正是所谓闭包的特性。当一个函数返回它内部定义的一个函数时,就产生了一个闭包,闭包不但包括被返回的函数,还包括这个函数的定义环境。
    上面例子中,当函数generateClosure() 的内部函数 get 被一个外部变量 counter 引用时,counter 和generateClosure() 的局部变量就是一个闭包。
    如果还不够清晰,下面这个例子可以帮助你理解:
    var generateClosure = function() {
    var count = 0;
    var get = function() {
    count ++;
    return count;
    };
    return get;
    };
    var counter1 = generateClosure();
    var counter2 = generateClosure();
    console.log(counter1()); // 输出 1
    console.log(counter2()); // 输出 1
    console.log(counter1()); // 输出 2
    console.log(counter1()); // 输出 3
    console.log(counter2()); // 输出 2
     
    上面这个例子解释了闭包是如何产生的:counter1 和 counter2 分别调用了 generate-Closure() 函数,生成了两个闭包的实例,它们内部引用的 count 变量分别属于各自的运行环境。
    我们可以理解为,在 generateClosure() 返回 get 函数时,私下将 get 可能引用到的 generateClosure() 函数的内部变量(也就是 count 变量)也返回了,并在内存中生成了一个副本,之后 generateClosure() 返回的函数的两个实例 counter1和 counter2 就是相互独立的了。
     
    html:
    <ul>
      <li id="a1">aa</li>
      <li id="a2">aa</li>
      <li id="a3">aa</li>
    </ul>
     
    js:
    var lists = document.getElementsByTagName("li");
        for(var i=0; i<lists.length; i++){
            //i最后等于3 
            //想办法保存住i的值=>想到闭包
            function saveI(i){
                lists[i].onclick = function(){
                  alert(i)
                }
            }
            
            saveI(i);
        } 

     js:

    var lists = document.getElementsByTagName("li");
    for(var i=0; i<lists.length; i++){
            lists[i].onclick = function(){
                //这里this的指向是没问题的 只是i的值不能保留
                alert(this.getAttribute('id'))
            }
    } 
     
    2. 闭包的用途
    嵌套的回调函数
    闭包有两个主要用途:
    (1)是实现嵌套的回调函数
    (2)是隐藏对象的细节
    JavaScript通过约定在所有私有属性前加上下划线(例如_myPrivateProp)
     
     
  • 相关阅读:
    程序员:不要自称为码农
    SpringBoot对静态资源配置
    LeetCode 572. Subtree of Another Tree(子树)
    LeetCode 437. Path Sum III(统计路径和等于sum的路径数量)
    LeetCode 112. Path Sum(判断路径和是否等于一个数)
    LeetCode 617. Merge Two Binary Trees(归并两棵二叉树)
    LeetCode 226. Invert Binary Tree(翻转二叉树)
    Failure to transfer org.apache.maven.plugins:maven-resources-plugin:pom:2.6 的解决办法
    linux-查询某软件的安装的目录
    WebService概念解释
  • 原文地址:https://www.cnblogs.com/zqzjs/p/5090277.html
Copyright © 2011-2022 走看看