JavaScript垃圾回收与闭包举例详解

垃圾回收

标记清除

当变量进入环境时,将其标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。垃圾回收器会销毁那些带标记的值,并回收它们所占用的内存空间。

function test() {
  var a = 1; // 函数调用时 被标记 进入上下文
}
test(); // 函数执行完毕,a的标记去掉,被回收

引用计数

当声明一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。当垃圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。

function test() {
  var a = {}; // a的引用次数为0,被回收
  var b = a; // a的引用次数加1,为1
  var c = a; // a的引用次数再加1,为2
  a = 1; // a的引用次数减1,为1
  b = 1; // a的引用次数减1,为0,可以被回收了
  c = 1; // a的引用次数减1,为0,可以被回收了
}

闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。闭包使得函数可以继续访问定义时的词法作用域。

闭包的另一个用处,是封装私有变量。

function createCounter() {
  let count = 0;
  return {
    increment: function () {
      count++;
    },
    getCount: function () {
      return count;
    },
  };
}

const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 1

闭包的缺点:

  • 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
  • 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
  • 闭包的缺点就是常驻内存,会增大内存使用量,并且使用不当很容易造成内存泄露。

闭包的用途

  • 创建私有变量
    function createCounter() {
      let count = 0;
      return {
        increment: function () {
          count++;
        },
        getCount: function () {
          return count;
        },
      };
    }
    

  • 模拟块级作用域
    (function () {
      for (var i = 0; i < 10; i++) {
        console.log(i);
      }
    })();
    

  • 实现柯里化
    function add(a, b, c) {
      return a + b + c;
    }
    
    function curry(fn) {
      return function curried(...args) {
        if (args.length >= fn.length) {
          return fn.apply(this, args);
        } else {
          return function (...args2) {
            return curried.apply(this, args.concat(args2));
          };
        }
      };
    }
    
    const curriedAdd = curry(add);
    console.log(curriedAdd(1)(2)(3)); // 6
    

  • 实现函数节流和防抖
    function throttle(fn, delay) {
      let timer = null;
      return function (...args) {
        if (!timer) {
          timer = setTimeout(() => {
            fn.apply(this, args);
            timer = null;
          }, delay);
        }
      };
    }
    
    function debounce(fn, delay) {
      let timer = null;
      return function (...args) {
        clearTimeout(timer);
        timer = setTimeout(() => {
          fn.apply(this, args);
        }, delay);
      };
    }
    

  • 实现单例模式
    function Singleton(fn) {
      let instance = null;
      return function (...args) {
        if (!instance) {
          instance = new (fn.bind(this, ...args))();
        }
        return instance;
      };
    }
    
    function User(name) {
      this.name = name;
    }
    
    const createUser = Singleton(User);
    const user1 = createUser('Alice');
    const user2 = createUser('Bob');
    console.log(user1 === user2); // true
    

  • 实现模块化开发
    const module = (function () {
      let privateVar = 0;
      function privateFunc() {
        console.log('privateFunc');
      }
      return {
        publicFunc: function () {
          console.log('publicFunc');
        },
      };
    })();
    module.publicFunc(); // publicFunc
    module.privateFunc(); // TypeError: module.privateFunc is not a function

总结 

到此这篇关于JavaScript垃圾回收与闭包的文章就介绍到这了,更多相关JS垃圾回收与闭包内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

来源链接:https://www.jb51.net/javascript/3389177wu.htm

© 版权声明
THE END
支持一下吧
点赞7 分享
评论 抢沙发
头像
请文明发言!
提交
头像

昵称

取消
昵称表情代码快捷回复

    暂无评论内容