JavaScript - 闭包

108 阅读2分钟

前言

本文是作者学习笔记,欢迎指正。

本文多处知识点涉及 js预编译过程V8引擎的垃圾回收机制

闭包的定义

《你不知道的JavaScript》

当函数可以记住并访问所在的词法作用域时,就产生了闭包。即函数是在当前词法作用域之外执行。

MDN

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。

优缺点?

优点

  1. 实现封装,属性私有化,防止污染全局变量。
  2. 保护作用域不被释放,成员变量被缓存起来具有记忆性。
  3. 模块开发,

缺点

  1. 闭包会导致作用域链不释放,造成内存泄漏。

因内存调试的几个案例而引发的思考

本案例是用谷歌浏览器-开发者工具中的内存快照进行实验。也使用了nodejs的process模块,发现二者有差别。以谷歌V8引擎为案例

num内存未释放, 闭包!:

let count = (function () {
    let num = new Array(5 * 1000 * 1000).fill(0);
    function addNum () { num.push(1); }
    function getNum () { return num; }
    return {
        addNum,
        getNum
    };
})();

num内存未释放 :

let count = (function () {
    let num = new Array(5 * 1000 * 1000).fill(0);
    function addNum () { num.push(1); }
    return function(){
        console.log('num引用没有保存到外部!');
    }
})();

num内存释放:

let count = (function () {
    let num = new Array(5 * 1000 * 1000).fill(0);
    return function(){}
})();

num2的内存释放,num1内存没有被释放:

let count = (function () {
    let num = new Array(5 * 1000 * 1000).fill(0);
    let num2 = new Array(5 * 1000 * 1000).fill(0);
    function addNum () { num.push(1); }
    return function () { }
})();

总结

  • 由上述案例垃圾回收机制的存在,闭包的形成与函数作用域中的的引用关系有关。
  • 我理解的闭包为,闭包可以存储函数和该函数所在的词法作用域内相关联的环境变量, 无关的环境仍会被垃圾回收机制清除掉。