JavaScripts如何理解中的闭包closure

2021-05-24 09:30 JavaScript日志

闭包是 JavaScript 一个重要的知识点,在面试的时候八九不离十的会被问到,本章我们来一起聊聊闭包

什么是闭包?

闭包的定义:个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。闭包 - JavaScript | MDN闭包的定义:个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。

我的理解:一个能访问外部变量的内存函数,就是闭包。

代码示例:

function fn1 () {  let num = 0  return function() {    // 内部函数访问了外部函数的变量 num    // 这就算是一个闭包    num ++    return num  }}
const numFn = fun1()numFn() // num -> 1numFn() // num -> 2numFn() // num -> 3

从示例中我们可以看到每一次调用 fn1 的内部函数,num都进行了 + 1,这也是闭包的一个特点:外层的变量如果在闭包中使用了,能够保持活跃不被回收(缓存外层函数的数据)

我们来实现几个闭包的使用场景:

· 实现 add() 函数,使其可以 add(1)(2) 调用(这是一道经常出现的面试题)

function add(val) {  let num = val  return function fn(val) {    // 如果是最后一次执行,就返回 num    if(!val) {      return num    }    num += val    // 每次放回自己,可以连续调用    return fn  }}
console.log(add(2)(3)(5)())

· 我们还可以通过闭包模拟私有方法,下面是一个简单的计数器实现:

const counter = (function() {  // 私有变量:存储当前计数  let num = 0  // 私有方法,更改当前计数  function change(val) {    num += val  }  // 提供一些开发的方法  return {    getValue() {       return num     },    increment: function() {      change(1);    },    decrement: function() {      change(-1);    }  }})()counter.increment()counter.getValue() // num -> 1counter.decrement()counter.getValue() // num -> 0

闭包的错误打开方式

1、循环中使用闭包

function fn() {  let num = 1  const handles = []  for(let i = 0; i < 3; i++) {    num += i    handles.push(function f () {      return num    })  }  return handles}const handles = fn()console.log(handles)handles.forEach(fn => {  // handles中每个方法的返回值都会是:4  // 因为每一个方法都共用了同一个变量  console.log(fn())})

2、滥用的闭包:

我们在上方讲到了 闭包能够保持外层变量 保持活跃,那么如果大量使用闭包,可能会导致内存泄漏

在 MDN 文档中还聊到了闭包的性能考量的内容具体可以去阅读一下

如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响。




图片

-- 火把倒下,火焰依然向上 --

本文章转载自公众号:JavaScript_log

首页 - JavaScript 相关的更多文章: