zoukankan      html  css  js  c++  java
  • Javascript 闭包

           当函数在当前的词法作用域之外执行,函数可以记住并访问该函数所在的词法作用域时,就产生了闭包。当函数跳出当前的词法作用域之外,但是该函数的作用域链有对它所在的词法作用域的引用,这样采用标记--清除算法的Javascript垃圾回收机制,就能够从根部出发找到该词法作用域,因此,该词法作用域不会被垃圾回收。这样该块词法作用域可以和全局变量一样存储在内存中,直到没有引用指向该块词法作用域(也就是从根出发无法找到该块词法作用域)时,该词法作用域才会被js的垃圾回收机制回收。     

    function Test(){
      for (var i =1 ; i<=5; i++)
      {
         setTimeout(function Timer(){
             console.log(i)}, i*1000);
      }
    }

              上面的例子也是闭包的一种,即函数在当前的词法作用域之外被调用。该函数最终会以每秒一次输出的频率输出5个6,因为没有块级作用域,Timer 作用域链中的 i 都是引用函数外部的i,当当前js主线程执行完,Timer()函数从事件队列返回到js线程执行时,此时 i=6。 

          如何能够让该函数以每秒一次的频率输出1~5呢?

          这时就要为每次调用的setTimeout()函数创建一个函数作用域:

    for(var i =1 ;i <=5 ;i++)
    {
       (function (j){
           setTimeout(function Timer(){
              console.log(i)}, i*1000);})(i);
    }

       Js 在创建函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链被保存在内部的[[Scope]] 属性中。当调用函数时,会为函数创建一个执行环境,然后通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链。在函数内部定义的函数会将外部函数的活动对象(即外部函数定义的所用变量的对象)添加到该函数的作用域链中。在下面的例子中,函数state和setState都会将由变量_val,noargs组成的活动对象添加到自己的作用域链中,所以调用这个两个函数能够对这两个变量进行读写操作。而在useState外部创建_val时,会在当前的作用域中添加一个变量,值为initiValue。当setVar({aa:1000})执行后,再次访问该变量时,只能在当前的作用域中找到之前赋初始值的变量,无法访问复制到setSate和state函数作用域链中的变量。也就是一个函数在执行完,函数内部的局部活动对象会被销毁,只是当有闭包存在时,函数的内部活动对象的引用会被复制到闭包函数的作用域链中,相当于外部函数的活动对象被销毁了,只是在销毁之前被复制了一份到内部函数的作用域链中。也就是只用形成闭包的函数的内部才能访问到外部函数的活动对象。

     1 function useState(initialValue) { 
    2
    var _val = initialValue 3 var noargs = initialValue 4 5 function state() { 6 return "_val.aa="+_val.aa +" noargs.aa="+ noargs.aa 7 } 8 function setState(newVal) { 9 noargs = newVal 10 _val = newVal 11 } 12 return [noargs, state, setState] 13 } 14 15 const [_var,getVal,setVar] = useState({aa:10}) 16 17 setVar({aa:1000}) 18 19 console.log(_var,getVal())

    // 输出: {aa:10}
    // _val.aa=1000 noargs.aa=1000

      由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用会导致内存占用过多的问题。

      


  • 相关阅读:
    怎样检测数据类型
    怎样理解函数参数的传递
    怎样在微信H5中点击直接跳转到公众号
    怎样启动和关闭nginx服务器
    怎样测试nginx.conf配置文件的正确性
    怎样查找/搜索文件
    怎样创建用户组并添加用户进用户组
    怎样查看Nginx版本号
    怎样写一个Hello World!
    怎样理解基本类型(原始类型)的数据和引用类型的数据
  • 原文地址:https://www.cnblogs.com/wust-hy/p/7349154.html
Copyright © 2011-2022 走看看