了解Javascript中闭包

79 阅读4分钟

闭包是什么?

我们先解释一下:闭包是一个概念,当我们在函数内部定义了其他函数的时,就创建了闭包.

ps:闭包在使用时通常被称为闭包函数.

闭包函数可以访问其定义时所处作用域中的变量.

并且可以将变量保存在函数内部,使得变量函数外部也可以被访问和修改.

因此,闭包函数常常用于 实现回调函数 、事件处理程序 等需要访问外部变量的场合.

更简单的理解是:闭包就相当于嵌套函数,因为嵌套函数也可以访问包含它函数的变量.

闭包一定会在函数创建的同时被创建出来吗?

不一定,一般来说,JavaScript中的函数都可以是闭包;

但完整的说法应该是: 一个普通的函数function,如果它可以访问外层作用域的自由变量,那么这个函数就是一个闭包.

闭包和函数有关系吗?

  • 函数是一段可重复使用的代码块,它可以接受参数并返回值.

    而闭包是指一个函数能够访问并操作其外部函数作用域中的变量,即使外部函数已经执行完毕,这些变量仍然可以被访问和操作.

  • 函数本身不存储任何信息,只有与引用环境结合后形成的闭包才具有‘记忆性’.

    闭包可以看作是一种特殊的函数,它可以“记住”其创建时的环境,即使在其他地方调用它时,它仍然可以访问这些变量.

简化一下,函数是一段代码块,它可以被多次调用,每次调用时可以传入不同的参数,执行完毕后可以返回一个值。

而闭包算是一个函数,它可以访问其外部函数作用域中的变量,即使外部函数已经执行完毕,这些变量仍然可以被访问和操作。

为什么要使用闭包

闭包可以让内部函数访问到外部函数作用域中的变量,同时也可以将函数中的变量存储到内存中,保护变量不被污染。闭包可以将函数内部和函数外部连接起来.在实际开发中,闭包可以用来实现模块化、封装变量、实现私有成员等功能。

举个例子,比如我们要创建一个计数器,但是不希望外部直接访问和修改计数器的值,可以使用闭包来实现:

 function createCounter() {
  var count = 0;
  return function() {
    count++;
    console.log(count);
  }
}

var counter = createCounter();
counter(); // 输出1
counter(); // 输出2
counter(); // 输出3

在这个例子中,我们使用了闭包来创建了一个私有变量count,并返回了一个函数,这个函数可以访问和修改count的值。外部只能通过调用返回的函数来访问和修改count的值,而无法直接访问和修改count的值,从而保护了count的安全性。

闭包有什么缺点嘛

1 闭包会使得函数中的变量都被长久保存在内存中,增加内存使用量

所以,如果闭包被滥用,可能会导致内存泄漏,并且会占用大量内存,导致变量不会被垃圾回收机制回收,从而影响程序的性能

因此,在使用闭包时,需要注意合理使用,避免滥用和过度使用,以免影响程序的性能和稳定性。

JS垃圾回收机制

JS规定在一个函数作用域内,程序执行完以后变量就会被销毁,这样可节省内存

而使用闭包时,按照作用域链的特点,闭包(函数)外面的变量不会被销毁,因为函数会一直被调用,所以一直存在,如果闭包使用过多会造成内存销毁!!!

闭包造成的内存泄漏怎么解决呢?

内存泄露是指:用动态存储分配函数内存空间,在使用完毕后未释放,导致一直占据该内存单元,直到程序结束。指任何对象在你不再拥有或需要它之后仍然存在。

闭包造成的内存泄漏可以通过以下方法进行解决:

1 及时清除定时器和回调函数,避免它们一直存在而导致内存泄漏.

2当不需要使用闭包时,要及时释放内存,可将内存函数对象的的变量赋值为 null。 让垃圾回收机制回收内存。

举个例子,如果在使用闭包的过程中,定义了一个块级作用域变量instance,每次使用完毕后都要手动将其赋值为null,以便让垃圾回收机制回收内存。具体代码如下:

      function Na(params) {  
          this.color = [12]  
          this.name = 'jacky'  
        }  

        Na.prototype.say = function father() {  
          let self = this;  
          return function son() {  
            console.log('self.color',self.color)  
            return self.color  
          }  
        }  

        let instance = new Na();  
        console.log('instance', instance);  
        instance.say() // 我对say方法使用完毕了,后续都不会在使用instance这个实例对象的引用;  
        instance = null// 释放instance的内存,让这个变量被垃圾回收机制给回收走。  

-------------------------------------------byby-------------------------------------------