javascript之闭包

什么是闭包

含义:是指有权访问另一个函数作用域中的变量

优点:可以重复使用,并且不会造成变量污染。(全局变量可以重复使用,但是容易造成变量污染。局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。闭包则结合了全局变量和局部变量的优点)

缺点:比普通函数更占用内存,函数调用后不会销毁变量容易导致网页性能变差,在IE下容易造成内存泄漏

 

可能造成内存泄漏的原因:

1、意外的全局变量(在函数内部没有使用var进行声明的变量)

2、console.log

3、闭包

4、对象的循环引用

5、未清除的计时器

6、DOM泄露(获取到DOM节点之后,将DOM节点删除,但是没有手动释放变量,拿对应的DOM节点在变量中还可以访问到,就会造成泄漏)

闭包造成内存泄漏的原因:

因为闭包就是能够访问外部函数变量的一个函数,而函数必须是保存在内存中的对象,所以位于函数执行上下文中的所有变量也需要保存在内存中,这样就不会被回收,如果一旦循环引用或创建闭包,就会占据大量内存,可能会引起内存泄漏。

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

1、将闭包引用的外部函数中活动对象清除(引用变量清除)

2、避免变量的循环赋值和引用

闭包应用

 

1、函数防抖:就是指触发事件后在秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行事件(通俗的说:在一段固定的时间内,只能触发一次函数,在多次触发事件时,只执行最后一次)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>函数防抖</title>
</head>
<body>
    <div id="id" style="width:40px;height:40px;line-height:40px;border:1px solid #ddd;text-align:center">2</div>
    <script>
    //======闭包实例:函数防抖===== 
    var num = 2;
    var el = document.getElementById('id');
    console.log(el,'el')
    function count() {
        el.innerText = ++num;
    }
    count()
    /**
    * @function debounce 函数防抖
    * @param {Function} fn 需要防抖的函数
    * @param {Number} interval 间隔时间
    * @return {Function} 经过防抖处理的函数
    */
    function debounce(func, wait) {
        let timer;
        return function() {
            let _this = this;
            let args = arguments;
            if(timer) clearTimeout(timer);
            timer = setTimeout(()=> {
                func.apply(_this,args);
            },wait);
        }
    }
    el.onmousemove = debounce(count,1000);
    </script>
</body>
</html>

2、函数节流:就是限制一个函数在一定时间内只能执行一次

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>函数节流</title>
</head>
<body>
    <div id="id" style="width: 80px;height: 40px;line-height:40px;text-align: center;border: 1px solid #ddd;cursor:pointer;font-size: 12px;">2</div>
    <script>
        /** 闭包实例:函数节流 */
        let el = document.getElementById('id');
        let num = 2;
        function count() {
            el.innerHTML = ++num;
            console.log(num,'num')
        }
        /**
        * @function throttle 函数节流
        * @param {Function} fn 需要节流的函数
        * @param {Number} interval 间隔时间
        * @return {Function} 经过节流处理的函数
        */
        function throttle(fn, interval) {
            let timer = null;
            let firstTime = true;
            return function() {
                let args = Array.prototype.slice.call(arguments,0);
                let _this = this;
                if(firstTime) {
                    fn.apply(_this, args);
                    firstTime = null;
                }if(timer) return;
                timer = setTimeout(() => {
                    fn.apply(_this, args);
                    timer = null;
                },interval || 300)
                console.log(timer,'timer')
            }
        }
        el.onmousemove = throttle(count, 1000);
    </script>
</body>
</html>

 

函数防抖与函数节流的区别:

案例:设定一个间隔时间为1秒,在一分钟内,不断移动鼠标,让它触发一个函数(触发次数远远大于60次),打印一些内容。

结果:

函数防抖:会打印一次,在鼠标停止移动的一秒后打印。

函数节流:会打印60次,因为在一分钟内有60秒,每秒会且仅会触发一次。

总结:节流是为了限制函数的执行次数,而防抖是为了限制函数执行时机(只执行最后一次)

3、其他应用:

/**
 * 不使用循环返回数组
 */
  function getNewArr() {
      let n = 6;
      let newArr = [];
      return (function() {
                newArr.unshift(n);
                n--;
                console.log(newArr,'数组',n)
                if(n>0) {
                    arguments.callee();//递归调用本函数
                }
                return newArr
        })()
  }
  getNewArr()

 

posted @ 2020-12-01 16:56  #青橙#  阅读(78)  评论(0编辑  收藏  举报