JS中的闭包问题

什么是闭包

闭包是指一个函数与其引用的非局部变量(也称作自由变量)的组合。在一个函数内部,如果定义了一个内部函数并引用了外部函数的变量,则称这个内部函数是一个闭包。闭包函数可以访问外部函数中的变量,即使这些变量在外部函数执行完毕后已经销毁,闭包函数依然可以引用它们,因为它们被绑定到了闭包函数中。

即我们在理解闭包的前提下,首先要掌握作用域、垃圾回收机制、作用域继承等相关知识

什么是作用域

在大多数编程语言中,变量的作用域可以分为全局作用域和局部作用域。全局作用域指的是在程序的任何地方都能够访问的变量,而局部作用域指的是只能在某个特定的代码块中访问的变量。在函数中,函数参数和局部变量也有自己的作用域。

作用域规则可以影响变量的生命周期和可见性。如果一个变量在其作用域之外被引用,可能会导致未定义行为或错误。因此,在编写程序时,需要注意作用域规则,以确保程序的正确性和可维护性。

即如下代码,我们在全局作用域下定义了一个变量a,因此无论在哪里都能访问到变量a的值,但是我们在函数fun的作用域下定义了一个变量b,则我们只能在函数fun的作用域下才能访问到变量b,而离开了其作用域,就无法访问到对应的变量的值,或抛出b is not defined 的异常

    var a = 10;
    function fun(){
      var b = 10;
    }
    console.log(a);
    console.log(b);

什么是垃圾回收机制

JavaScript 中的垃圾回收机制是自动的,它由 JavaScript 引擎来完成。JavaScript 引擎使用一种称为垃圾收集器(Garbage Collector)的机制来跟踪和释放不再使用的内存。

JavaScript 引擎使用标记清除(Mark-and-Sweep)算法来管理内存。该算法的工作方式如下:

  1. 引擎将内存分为堆和栈两部分,栈是一个有限的空间,存储程序中的基本数据类型和引用类型的变量。

  1. 所有在栈中的变量都可以直接被访问,而在堆中存储的数据则需要通过引用才能访问。

  1. 当 JavaScript 中的对象不再被引用时,垃圾收集器会将其标记为垃圾。

  1. 垃圾收集器会定期运行,将所有标记为垃圾的对象从内存中删除,释放它们所占用的内存空间。

垃圾回收器在什么时候运行是由 JavaScript 引擎自行决定的。在大多数情况下,它会在内存不足时运行,但也可以通过手动触发来运行。尽管垃圾回收机制是自动的,但是编写高效的 JavaScript 代码和避免创建过多的对象可以帮助减少垃圾回收的次数,从而提高性能。

什么是作用域继承

即在JS中,当我们在查找一个变量时,首先会在当前作用域中进行查找,若发现则输出,若没有发现,则会在当前作用域的外面查找,若没找到则依次向外查找,直到找到全局作用域下。

JavaScript 中的作用域继承可以用来实现一些高级的编程技巧,比如闭包。闭包是指一个函数可以访问其定义时所在的作用域中的变量,即使该函数在其定义所在的作用域之外被调用。这是因为函数的作用域链中包含了定义时所在的作用域,这种特性可以用来实现一些高级的编程技巧,比如模块化编程等。

需要注意的是,作用域继承是单向的,即内层作用域可以访问外层作用域中的变量和函数,但是外层作用域不能访问内层作用域中的变量和函数

那什么是闭包

闭包就是在函数内部定义一个函数,并将该函数作为返回值返回给外部使用。由于内部函数可以访问外部函数的变量和函数,所以在外部函数执行完毕后,返回的内部函数依然可以访问外部函数的变量和函数。通过下面这段代码,在outer函数的内部定义了一个inner函数,并把inner函数的返回值作为outer内部定义的一个值,你会发现,我们不断调用outer函数的时候,输出的值会依次加1,即outer内部定义的变量不会因为outer函数执行后被收回。

function outer() {
  var x = 10;
  function inner() {
    x += 1;
    console.log(x);
  }
  return inner;
}

var innerFunc = outer();
innerFunc(); // 输出 11
innerFunc(); //12
innerFunc(); //13

闭包的注意事项

由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

你可能感兴趣的:(JS,javascript,前端,开发语言)