深度剖析闭包原理及使用场景

1,710 阅读2分钟

作用域与作用域链

  • 作用域
  1. 作用域为可访问变量,对象,函数的集合,即变量可用范围;
  2. 局部作用域:变量在函数内声明,变量为局部作用域,只能在函数内部访问;
  3. 变量在函数外定义,即为全局变量。全局变量有 全局作用域,网页中所有脚本和函数均可使用;
  4. JavaScript 变量生命周期在它声明时初始化。局部变量在函数执行完毕后销毁。全局变量在页面关闭后销毁。
  • 作用域链
  1. 访问某个变量时,一层一层的沿着父元素往上找,找到就停止,如果最后没找到就抛出错误;
  • active object(AO)
    • AO是临时创建的活动对象,该对象包含了函数的所有局部变量,参数,以及this,当执行上下文的时候,就会被销毁,活动也会被销毁;
    <script>
        let num = 10;

        function addNum() {
            let num = 0;
            num++;
            console.log(num);
        }
        addNum();
        console.log(num);
    </script>

以上代码执行过程:

  • V8引擎解析js原理

闭包的构成及应用场景

  • 闭包作用域
<script>
        function outer() {
            let a1 = 0;
            let a2 = 1;
            return function inner() {
                return a1;
            }
        }

        function testClosure() {
            let getInnerData = outer();
            console.dir(getInnerData);
        }
        testClosure();
    </script>

为什么上图的闭包作用域里面只有a1没有a2?因为a1被引用了,但是a2没被引用,被垃圾回收了。

  • 闭包的使用场景
    • 防抖、节流
    • 用闭包模拟私有方法
    let Counter = (function() {
            let privateCounter = 0;
            //私有方法
            function change(val) {
                privateCounter += val;
            }
            return {
                increment: function(val) {
                    change(val);
                },
                decrement: function(val) {
                    change(-val);
                },
                value: function() {
                    return privateCounter;
                }
            }
        })();
        console.log(Counter.value())
        console.log(Counter.increment(1))
        console.log(Counter.increment(1))
        console.log(Counter.value())
        //打印出0和2
    
let makeCounter = function() {
            let privateCounter = 0;
            //私有方法
            function change(val) {
                privateCounter += val;
            }
            return {
                increment: function(val) {
                    change(val);
                },
                decrement: function(val) {
                    change(-val);
                },
                value: function() {
                    return privateCounter;
                }
            }
        };
        var Counter1 = makeCounter();
        var Counter2 = makeCounter();
        console.log(Counter1.value());
        Counter1.increment(1);
        Counter1.increment(1);
        console.log(Counter1.value());
        console.log(Counter2.value());
        //打印出0 2 0

原因:每个闭包引用各自词法作用域的变量,实现数据的隐藏和封装;

闭包性能考量

闭包子处理速度和内存消耗方面对脚本性能有负面影响;