美文网首页
什么是闭包?

什么是闭包?

作者: 小碗碗碗碗 | 来源:发表于2020-06-29 15:47 被阅读0次
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。
                                                  —— 你不知道的JavaScript(上卷)

一、闭包的定义

1、闭包的构成
首先,闭包由两部分构成:函数创建该函数的环境,环境由闭包创建时在作用域中的任何局部变量组成。

JS的变量作用域
变量的作用域有两种:全局变量和局部变量。
函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。

那么,如何从外部读取函数内部的局部变量?在下面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。
这就是Javascript语言特有的 链式作用域 结构(chain scope):子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,就可以在f1外部读取f1的内部变量。

function f1(){
  var n=999;
  function f2(){
    alert(n); 
  }
}
var test = f1();// 外部函数调用之后其变量对象n本应该被销毁
test();// alert 999,但闭包阻止了它们的销毁,所以仍然可以访问外部函数的变量对象

上面代码中的f2函数,就是闭包。
在JS中,只有函数内部的成员才能读取局部变量。所以在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

二、闭包的特性

在JavaScript中,外部函数调用之后其变量对象本应该被销毁,但闭包阻止了它们的销毁,所以仍然可以访问外部函数的变量对象。

function addCalculator (x) {
    return function (y) {
        return x + y;
    }
}

var add1 = addCalculator(1);
console.log(add1(1)); //2

add1 = null;// 释放对闭包的引用
console.log(add1(1)); //Uncaught TypeError: add1 is not a function

通常情况下,函数的作用域及其所有变量都会在函数执行结束后被销毁。
但如果创建了一个闭包的话,这个函数的作用域就会一直保存到闭包不存在为止。

闭包的特性一般为以下几点:
1、闭包一般为外部函数嵌套的内部函数、以及创建该内部函数的环境组成的;
2、闭包可以引用外部函数的参数和变量,即可以访问外部的环境;
3、闭包未被释放回收的情况下,若闭包中引用了外部函数的参数和变量,即使外部环境已经被释放回收,但是外部函数的参数和变量依然不会被垃圾回收机制回收。

三、闭包的作用

1、通过闭包来模拟私有方法
私有方法有利于限制对代码的访问,而且可以避免非核心的方法干扰代码的公共接口,减少全局污染。
下面的示例展现了如何使用闭包来定义公共函数,并令其可以访问私有函数和变量。这个方式也称为模块模式(module pattern)

var calculator = (function(){
    var a = 1;
    function addCalculator(val){
        a += val
    }
    return {
        add1:function() {
            addCalculator(1);
        },
        add2:function() {
            addCalculator(2);
        },
        result:function() {
            return a
        }
    }
})();

console.log(calculator.result());  // 1
calculator.add1();
console.log(calculator.result());  // 2
calculator.add2();
console.log(calculator.result());  // 4

在之前的示例中,每个闭包都有它自己的词法环境。而这次例子中只创建了一个词法环境,为三个函数所共享:calculator.add1,calculator.add2和 calculator.result。

该共享环境创建于一个立即执行的匿名函数体内。这个环境中包含两个私有项:名为 a的变量和名为 addCalculator的函数,这两项都无法在这个匿名函数外部直接访问,必须通过匿名函数返回的三个公共函数访问。

这三个公共函数是共享同一个环境的闭包,它们都可以访问 a变量和 addCalculator函数。

四、闭包的优缺点

1、优点

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

2、缺点

  • 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以滥用闭包的话会造成网页的性能问题,在IE(IE9)之前可能导致内存泄露。
    解决方法:在退出函数之前,将不使用的局部变量全部删除(例如手动赋值为null)
  • 由于闭包涉及跨域访问,所以会导致性能损失。
    解决方法:可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响。

引申:为何闭包的不当使用会在IE(IE9)之前可能导致内存泄漏,即无法回收变量的问题?
因为IE(IE9)之前的JavaScript引擎使用的垃圾回收算法是引用计数法,对于循环引用将会导致GC(Garbage Collection)无法回收垃圾。
注:在后面的章节中,我会找机会继续讨论什么是GC(Garbage Collection)

PS:更新来啦O(∩_∩)O,下一篇文章讲到了GC(Garbage Collection):JS的垃圾回收机制

相关文章

  • 前端常见问题总结

    什么是闭包?闭包的用途是什么?闭包的缺点是什么? 什么是闭包 闭包:内部函数总是可以访问其所在的外部函数中声明的参...

  • python函数部分

    什么是闭包,闭包的常用用法,怎样判断是不是闭包,闭包的作用是 1、什么是闭包 2、常用用法 3、判断是不是闭包 4...

  • 闭包、call-apply-bind 的用法 、HTTP状态码

    一、什么是闭包?闭包的用途是什么?闭包的缺点是什么? 答 :1、什么是闭包:如果一个函数用到了外部的变量,那么这个...

  • Escaping Closures - Swift

    逃逸闭包和非逃逸闭包 逃逸闭包(escaping closure),什么是逃逸闭包?苹果官方给的定义是:当一个闭包...

  • 深入解析Javascript闭包及实现方法

    一、什么是闭包和闭包的几种写法和用法 1、什么是闭包 闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的...

  • 面试题(day-2)

    1 ,什么是闭包?闭包有什么好处?使用闭包要注意什么? 闭包:函数嵌套函数,内部函数可以引用外部函数的参数和变量,...

  • 闭包,定时器

    问题 1.什么是闭包? 有什么作用 闭包(英语:Closure),又称词法闭包(Lexical Closure)或...

  • python函数之闭包

    目录 python函数之闭包什么是闭包python中的namespace闭包的条件闭包的优点 python函数之闭...

  • 再次学习 Swift 闭包

    Swift 闭包 1. 什么是闭包? 闭包是自包含的函数代码块,可以在代码中被传递和使用。 2. 闭包能做什么? ...

  • 前端面试题

    1 ,什么是闭包?闭包有什么好处?使用闭包要注意什么? 详情可参考:http://www.jianshu.com/...

网友评论

      本文标题:什么是闭包?

      本文链接:https://www.haomeiwen.com/subject/zzrdfktx.html