js面试题 闭包——closure

  • 闭包是由函数以及声明该函数的词法环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量。

定义:

        函数套函数,内部函数使用了外部函数定义的局部变量。

用处:

        1.读取函数内部的变量;

        2.这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除。

作用:

        1.希望一个变量长期驻扎在内存当中,不会被内存回收机制回收,即延长变量的生命周期

        2.避免全局变量的污染;

        3.私有成员的存在。

特性:

        1.函数套函数;

        2.内部函数可以直接使用外部函数的局部变量或参数;

        3.变量或参数不会被垃圾回收机制回收。

缺点:

          常驻内存 会增大内存的使用量 使用不当会造成内存泄露,详解:

        (1)由于闭包会将它的外部函数的作用域也保存在内存中,因此会比其他函数更占用内存,这样的话,如果过度使用闭包,就会有内存泄露的威胁。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

内存泄漏程序的运行需要内存。对于持续运行的服务进程,必须及时释放不再用到的内存,否则占用越来越高,轻则影响系统性能,重则导致进程崩溃。不再用到的内存,没有及时释放,就叫做内存泄漏。

  • 基本类型变量(Number 、Boolean、Undefined、String、Null)的值一般都是存在栈内存中,

  • 引用类型变量(Array、Object、Function)的值存储在堆内存中,栈内存存储对应空间地址

        (2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

    <script>
      function add() {
        var a = 1
        function fn() {
          return a++
        }
        return fn
      }
      var c = add()
      console.log(c()) //1
      console.log(c()) //2
      console.log(c()) //3
      a = 100
      console.log(c()) //4

      /*  
      //js垃圾回收机制影响,此法a的值不会变,因为没有全局变量调用
      console.log(add()()) //1
      console.log(add()()) //1
      console.log(add()())//1
      console.log(add()())//1 
      */
    </script>

问题:

        1 闭包有哪些应用场景?

       (1)柯里化函数

        为了避免频繁地调用具有相同参数的函数,可以将一个多参数的函数转化为一个单参数的函数,其实就是一个高阶函数

//普通函数
function getArea(w,h){
    return w * h;
}
const area1 = getArea(10,20);
const area2 = getArea(10,30);
const area3 = getArea(10,40);

//柯里化函数
function getArea(w){
    return function(h){
        return w * h;
    }
}
const getTenArea = getArea(10);

const area1 = getTenArea(20);
const area2 = getTenArea(30);
const area3 = getTenArea(40);

        (2)通过闭包实现变量/方法的私有化

function funOne(i){
    function getTwo(){
        console.log('参数:', i)
    }
    return getTwo;
}
const fa = funOne(100); 
const fb = funOne(200); 
const fc = funOne(300); 

        (3)匿名自执行函数

var funOne = (function(){
    var num = 0;
    return function(){
        num++;
        return num;
    }
})()

console.log(funOne());   // 1
console.log(funOne());   // 2
console.log(funOne());   // 3 

        (4)缓存一些结果

        比如:外部函数定义一个变量,内部函数可以获取或修改这个变量的值,从而就延长了这个变量的生命周期

function parent(){
    let list = [];
    function son(i){
        list.push(i);
    }
    return son;
}

const fn = parent();

fn(1);
fn(2);
fn(3);

        2 闭包的this指向

        闭包的this指向的是window

        3 如何避免闭包引起的内存泄漏?

        (1)在退出函数之前,将不使用的局部变量赋值为null;(示例如下)

 这段代码会导致内存泄露
    window.onload = function(){
        var el = document.getElementById("id");
        el.onclick = function(){
            alert(el.id);
        }
    }
    解决方法为
    window.onload = function(){
        var el = document.getElementById("id");
        var id = el.id;                       //解除循环引用
        el.onclick = function(){
            alert(id); 
        }
        el = null;                        // 将闭包引用的外部函数中活动对象清除
    }

         (2)避免变量的循环赋值和引用。 (示例如上)

         (3)利用Jquery释放自身指定的所有事件处理程序。
由于jQuery考虑到了内存泄漏的潜在危害,所以它会手动释放自己指定的所有事件处理程序。 只要坚持使用jQuery的事件绑定方法,就可以一定程度上避免这种特定的常见原因导致的内存泄漏。

这段代码会导致内存泄露
$(document).ready(function() {
    var button = document.getElementById('button-1');
    button.onclick = function() {
         console.log('hello');
         return false;
    };
});
当指定单击事件处理程序时,就创建了一个在其封闭的环境中包含button变量的闭包。而且,现在的button也包含一个指向闭包(onclick属性自身)的引用。这样,就导致了在IE中即使离开当前页面也不会释放这个循环。

用jQuery化解引用循环
$(document).ready(function() {
    var $button = $('#button-1');
    $button.click(function(event) {
        event.preventDefault();
        console.log('hello');
    });
});

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

记忆怪 bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值