当前位置: 移动技术网 > IT编程>开发语言>JavaScript > JS闭包

JS闭包

2018年12月19日  | 移动技术网IT编程  | 我要评论

什么是闭包?

  javascript和其他编程语言一样,也采用词法作用域,也就是说,函数的执行依赖于变量作用域.js函数对象的内部状态不仅包含函数的代密码逻辑,还必须引用当前的作用域。

  函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。

  这就是一个闭包,它可以在外部通过某一种手段(方法)可以访问到内部的变量:

<script type="text/javascript">
            function fun1(){
                var a = 100;
                function fun2(){
                    console.log(a);
                }
                return fun2;
            }

            var fun = fun1();
            fun()
</script>

 

闭包的特点:

  1)占内存:当内部的函数被保存到了外面,就会形成闭包,闭包导致原有的函数执行完成了以后作用域链不会得到释放

造成了内存的泄露

  2)保护私有变量的安全

 

闭包的应用:

  1)计数器:

    由于每次访问的都是同一个作用域,在函数掉用完一次之后并没有被回,反而更新了它的作用域,所以函数每调用一次,它的值就会更新,次数就会增加一次。

function add(){
           var num = 0;
           return function(){
              num++;
             console.log(num)
            }
  }
  var fun = add();
  fun()              //1
  fun()              //2

  

  2)做缓存结构  

    每调用一次jia函数它就会加一,每调用一次jian函数它就会减一,

function fun(){
  var num = 0;
  function jia(){
       num++;
   console.log(num);
   }
  function jian(){
      num--;
    console.log(num)
   }
    return [jia,jian];
}
var jia = fun()[0];
var jian = fun()[1];
jia()          //1
jian()         //-1
jia()          //2
jian()         //-2
 

    

   3)封装

 

实例

 利用闭包,解决循环添加事件遇到的作用域问题:

 

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <ul>
            <li>0</li>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>7</li>
            <li>8</li>
            <li>9</li>
        </ul>
        <script type="text/javascript">
            var lis = document.getelementsbytagname("li");
            for(var i = 0;i < lis.length;i++){
                lis[i].onclick = function(){
                    console.log(i)
                }
                /*(function(i){  
                    lis[i].onclick = function(){
                        console.log(i)
                    }
                })(i)*/
            }

    </script>
  </body>
</html>

 

  如上代码,获取li元素,然后为每个li循环添加一个单击事件,使单击同的li显示对应的类数组的索引。

 

  但实际上,却是这种情况:(如图)

   单击不同的li,控制台显示的都是10。

  这是因为,函数作用域的问题:

  1)先生成一个go

  2)预编译时

go = {
  lis : undefined
  i : undefined
   }
3)执行后
go = {
  lis : {}
  i : 10
}

4)函数调用后生成10个ao
   lis[i].ao(i = 0-9){  *10

}

   此时在lis[i]函数中并没有找到i,所以只能向上级寻找,所以找到上级的i为10。这也就是每次单击时输出都为10的原因了。

 

  现在我们用闭包来解决这个问题,把上面的那种方式注释,将其放到一个立即执行函数中,就形成了一个闭包。

<script type="text/javascript">
            var lis = document.getelementsbytagname("li");
            for(var i = 0;i < lis.length;i++){
//                lis[i].onclick = function(){
//                    console.log(i)
//                }
                (function(i){   //ec6之前解决的方法,有且只有这一种
                    lis[i].onclick = function(){
                        console.log(i)
                    }
                })(i)
            }
</scrip>

 

此时我们单击时就可以获取正确的索引值。

  此时的生成的go是同之前的go 相同的,只是在执行立即函数时分别生成了10个ao,

 {

    i : 0 - 9
   }

  当再次触发单击事件时,单击函数寻找的对象就成了父级的ao的i,即立即执行函数的10个ao中的i。所以单击第i个就会寻找到与之对应的i的值,也就是不同li的索引值。

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网