[ JavaScript ] 对闭包的理解和使用场景

181 阅读4分钟

对闭包的理解和使用场景

什么是闭包

首先,闭包是 JavaScript 这个语言的一个特点,主要的使用场景就是为了创建私有的变量。当然这个变量包含函数。

如果用一句话来解释的解释闭包的话,那么就是:

闭包就是一种阻止垃圾回收器将变量从内存中移除的方法,使创建变量的执行环境外面可以访问到该创建的变量。

闭包的原理

function saveEvent(){
  let num = 10;
  return function (){
    num++;
    console.log(num);
  }
};
const count = saveEvent();
count();
count();
count();
count = null;
console.log(count)

// 11
// 12
// 13

以上面这个为例,创建一个函数,在这个函数里面设置一个变量,可以理解为这个是这个 saveEvent 函数的私有变量再执行 num++ ,之后把 saveEvent 这个函数赋值给 count 这个变量,这个时候 count 这个变量是常驻在内存里的。

然后再每次执行 count() 的时候 ,他都会给这个 num 进行累加,知道将 count 设置为 null 之后 ,他才会进行清空,也就是回收。

这个例子就是利用闭包完成了一个私有变量创建的例子。这里补充一点是,count 这个变量定义的虽然是 const ,count 定义的变量是不能够修改的,但是,这里的 count 是引用了 saveEvent 这个指针,所以,这个函数里面的参数怎么变化都是可以的。

闭包的好处和需要注意的地方

好处

闭包的好处通过上面的例子就可以得知,他可以使变量始终保存在内存中直到被销毁为止。另一个好处是,他可以创建私有属性或者方法,避免变量被全局变量污染。

需要注意的地方

闭包是能使变量常驻在内存中,这个是他的优点,但如果滥用闭包的话这个就变成了他的缺点。因为如果大量使用闭包存储变量,那么就会增加内存的消耗。 但其实以今天的各种设备来看,其实除了一些很大型的项目之外,只是我们在使用的时候稍微注意就好,也不会造成太大的影响。

闭包的常使用场景

函数表达式

在一般的情况下,我们使用函数定义的时候,是直接创建一个 function xx 然后再执行 xx();

那么,也可以用 () 是这个函数定义变成一个函数表达式。也就是我们常用的立即执行函数。

先看第一种写法

以这个例子来说,一个普通函数,使用闭包之后可以帮你创建一个对象保存在 car 这个变量中,这个 car 有着开始和颜色的两个方法。但是,我们在开发的过程中,不可能遇到一种情况就创建一个新变量,而是我们统一创建一个对象后存在一个变量,然后,其他的方法都可以去调用这边变量里面的属性,上古时期的产物 jQuery 就是一个大闭包。

function package() {
  const num = 123;
  const color = 'red'
  return {
    start: function () {
      console.log(num);
    },
    color: function () {
      console.log(color);
    }
  }
};
let car = package();
car.start();

可以改成下面的形式,给 params 赋值一个对象,而这个对象就是通过调用一次立即执行,返回的一个对象,再将这个对象存在变量中。

这个变量就有了该有的方法和属性,其他的函数都可以来调用他

let params = (function package() {
  const num = 123;
  const color = 'red'
  return {
    start: function () {
      console.log(num);
    },
    color: function () {
      console.log(color);
    }
  }
})()

params.start();
// 123

创建私有变量

let params = (function test() {
  function a() {
    const num = 123;
    return num;
  };
  function b() {
    const color = 'red'
    return color;
  };
  return {
    a: a,
    b: b
  }
})();
console.log(params.a());
//123

以这段代码为例,函数有两段 函数 a和b ,通过 return 出他们的函数之后,再使用 params.a() 调用。

代码模块化减少污染

let num = 3;
let params = (function test() {
  const num = 6;
  return {
    start: () => num * 2,
  }
})();
console.log(params.start());
// 12

很明显,num 这个参数是会优先取函数内部的数据,再执行。


现在还有人在使用 JQ 么?