zoukankan      html  css  js  c++  java
  • JS的闭合(Closure)

     

    定义

    MDN:函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。

    JS高程: 闭包是指有权访问另一个函数作用域中的变量的函数。

    Javascript权威指南:函数对象可以通过作用域关联起来,函数体内的变量都可以保存在函数作用域内,这在计算机科学文献中称为“闭包”,所有的javascirpt函数都是闭包

    你不知道的JS(上):当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前作用域外执行

    浏览器原理与实践:当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合称为闭包。比如外部函数是 foo,那么这些变量的集合就称为 foo 函数的闭包。

    各种书籍上对闭包的定义各不相同,但是我们没必要太过于纠结概念,只要我们深入理解他的含义和使用就可以了

    产生原因

    闭包产生与如下两个方面有关

    • 根据词法作用域的规则,内部作用域可以访问外部作用域
    • GC(垃圾回收)机制,如果变量被引用那么GC在回收时并不会回收该变量

    实例

        function foo() { 
            let test1 = '变量1'
            const test2 = '变量2'
            let test3 = '变量3'
            var innerBar = { 
                getName: function () { 
                    console.log(test1) 
                    return test2 
                },
            } 
            return innerBar 
        } 
        var bar = foo()
        bar.getName()

    我们可以通过控制台的Source中的scope看到闭包

    image.png

    右边 Scope 项就体现出了作用域链的情况:Local 就是当前的 getName 函数的作用域,Closure(foo) 是指 foo 函数的闭包,最下面的 Global 就是指全局作用域,从“Local–>Closure(foo)–>Global”就是一个完整的作用域链。

    注意⚠️:只有我们在内部函数中使用的变量才会被加入闭包(Closure)中。

    我们来看下范例中产生闭包时执行栈的情况:

    • 当执行到 foo 函数内部的return innerBar这行代码时调用栈的情况

    image.png

    • 当 foo 函数执行完成之后,其整个调用栈的状态(注意⚠️:此时foo执行上下文已出栈)

    image.png

    • 当执行到bar.getName()时的栈状态

    image.png

    通过上面三个图我们可以清晰的看到当前作用域链 是Local–>Closure(foo)–>Global。

    用途

    实现私有变量

    function Animal( ){
    
        //私有变量
        var series = "哺乳动物"function run( ){
            console.log("Run!!!");
        }   
    
        //特权方法
        this.getSeries = function(){
            return series;
        };
    }   

    实现模块模式

    var Counter = (function() {
      var privateCounter = 0;
      function changeBy(val) {
        privateCounter += val;
      }
      return {
        increment: function() {
          changeBy(1);
        },
        decrement: function() {
          changeBy(-1);
        },
        value: function() {
          return privateCounter;
        }
      }   
    })();
    
    console.log(Counter.value()); /* logs 0 */
    Counter.increment();
    Counter.increment();
    console.log(Counter.value()); /* logs 2 */
    Counter.decrement();
    console.log(Counter.value()); /* logs 1 */

    缺陷

    如果引用闭包的函数是一个全局变量,那么闭包会一直存在直到页面关闭;但如果这个闭包以后不再使用的话,就会造成内存泄漏。(如果引用闭包的函数是个局部变量,等函数销毁后,在下次 JavaScript 引擎执行垃圾回收时,判断闭包这块内容如果已经不再被使用了,那么 JavaScript 引擎的垃圾回收器就会回收这块内存)

    规避:如果该闭包会一直使用,那么它可以作为全局变量而存在;但如果使用频率不高,而且占用内存又比较大的话,那就尽量让它成为一个局部变量

     

  • 相关阅读:
    javascript
    javascript
    javascript
    easyui datagrid checkbox multiple columns have been done do
    combogrid获取多个字段的方法
    jquery显示、隐藏div的方法
    纠正jQuery获取radio选中值的写法
    comgrid获取多选值
    xheditor
    java向图片上写字,两个图片合并的方法
  • 原文地址:https://www.cnblogs.com/suihang/p/13402061.html
Copyright © 2011-2022 走看看