Js基础-闭包

1.闭包3特性、优缺点。

  1. 特性:
    ①函数嵌套函数
    ②函数内部可以引用函数外部的参数和变量
    ③参数和变量不会被垃圾回收机制回收

  2. 优缺点:

    ​ 优点:

    • 保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
    • 在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
    • 匿名自执行函数可以减少内存消耗

    ​ 缺点:

    • 被引用的私有变量不能被垃圾回收机制回收,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
    • 由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响。
  3. 闭包的用途,它的最大用处有两个:

    • 一个是前面提到的可以读取函数内部的变量
    • 另一个就是让这些变量的值始终保持在内存中。

2.我对闭包理解

  • 父函数中有个子函数,子函数用到父函数中的变量,子函数不会马上被执行,可能会通过 定时器 、 事件 、主动调用 去触犯子函数的执行,一旦子函数执行就创建闭包环境,这时候子函数就是一个闭包函数。
  • 如:通过调用父函数获取到的子函数就是闭包函数,它拥有自己一块空间,他用到的父函数中的变量不会被垃圾回收机制回收,被保存在相应的闭包空间中。
  • 每调用一次父函数就会创建一个闭包函数,同时开辟一块空间存放它。
  • 什么样的变量会让闭包函数开辟空间存放它?
    1. 父函数中的变量被相应的闭包函数用到,才会在相应的闭包函数中创建相应的同名变量,拿到父函数中变量值的作为初始值。(如2.1)
    2. 如果不是父函数中的变量,被闭包函数用到,并不会在闭包函数中创建同名变量。(如:2.3中,is不是在父函数中,而i被传递到父函数中,因此is无法在闭包函数中开辟空间存放它)
  1. 主动调用闭包函数,创建闭包空间

    function fn1() {
       var i = 1;
       
       function fn2() {
          return ++i;
       }
       return fn2;
    }
    
    var result1 =  fn1(); //获得闭包函数fn2
    result1();  //得到2
    result1();  //得到3
    
    var result2 =  fn1(); //获得闭包函数fn2
    result2();  //得到2
    result2();  //得到3
    
    //对吧result1,result2,说明每个闭包具有自己的空间,且用到的父级变量不会被回收。
    
  2. 定时器中创建闭包函数,处理变量值问题。

    //例:如何每隔一秒,依次从1输出到10?
    for(var i=0; i < 10; i++) {       
          setTimeout(function() {
               console.log(i);
           }, 1000);
    }
    //闭包解决:通过立即执行函数包裹定时器,立即执行函数每执行一次,定时器中的函数就会变成闭包函数同时创建一个闭包空间,变量i传到闭包空间中不会被回收,值被保存起来。
    for(var i=0; i < 10; i++) {
      (function(i) {
         setTimeout(function() {
            console.log(i);
         }, 1000);
      })(i); 
    }
    
  3. 什么样的变量会让闭包函数开辟空间存放它:闭包函数的父函数中的变量。

    var test = 1function fn () {
        var is = 100;  //这变量会被保存在相应闭包空间
        for(var i=0; i < 10; i++) {
          (function(i) {
            ++is
            setTimeout(function() {
              console.log(is);
              console.log(i);
              console.log(test); //test不会被保存在闭包中,因为他不在闭包的父函数中。
            }, 1000);
    
          })(i);
        }
      }
      fn();
    
  4. 点击事件中创建闭包,处理变量值问题。

//例:如何实现依次点击li,依次弹出:1、2、3、4。
var elements=document.getElementsByTagName('li'); 
var length=elements.length;   
for(var i=0;i<length;i++){   
  elements[i].onclick=(function(i) {
     function(){
      alert(i);
     }
  })(i)
}
//闭包解决:
for(var i=0;i<length;i++){     
  elements[i].onclick=function(){
      alert(i);
   //由于i是全局变量(被点击事件函数所依赖),所以不会被垃圾回收机制回收。 
  }
}

3.闭包作为参数传递

​ 闭包函数中用到其他作用域中的变量时,应该是从生命函数的地方往上找,而不是在调用的地方往上找。

var num = 15;
var fn1 = function(x) {
   if(x > num) {
     console.log(num)
   }
}
void function(fn2){
   var num = 100;
   fn2(30)
}(fn1)
//在这段代码中,函数fn1作为参数传入立即执行函数中,在执行到fn2(30)的时候,30作为参数传入fn1中,
//这时候if(x>num)中的num取的并不是立即执行函数中的num,而是取创建函数的作用域中的num这里函数创建的作用域是全局作用域下,所以num取的是全局作用域中的值15,即30>15,打印30

4.异步导致变量值出现问题,如何处理?

​ 解决方案:闭包、promise、asyns、let。

for(var i=0; i < 10; i++) {       
 setTimeout(function() 
        console.log(i);
    }, 1000);
}
  1. 处理:使用立即执行的函数表达式(IIFE)来捕获每次迭代时i的值。

    for(var i=0; i < 10; i++) {
      (function(i) {
         setTimeout(function() {
            console.log(i);
         }, 1000);
      })(i); 
    }
    
  2. 处理:利用块级作用域(最简单,推荐)。

    • let定义块级作用域变量,变量只在定义的花括号中有效
    • 不存在变量提升。而且要求必须 等let声明语句执行完之后,变量才能使用
    • let不允许在相同作用域内,重复声明同一个变量
    for(let i=0; i < 10; i++) {
     setTimeout(function() {
        console.log(i);
     }, 1000);
    }
    // 依次打印0 - 9
    
  3. 利用promise(使用promise的办法,是为了更好地理解promise)

    for(var i=0; i < 10; i++) {
        new Promise((resolve, reject) => {
          var j = i;
     setTimeout(function() {
         console.log(j)
     }, 1000);
        })
    }
    
  4. 利用async函数(为了理解async函数)

    async function foo() {
       for(var i=0; i < 10; i++) {
          let result = await new Promise((resolve, reject) => {
             setTimeout(function() {
                 resolve(i);
             }, 1000);
    });
             console.log(result);
       }
    }
    foo();
    // 每隔1s打印数字 0 - 9
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值