什么是闭包?
MDN:“闭包是捆绑在一起(封闭)的函数及其周围状态(词法环境)的引用的组合。换句话说,闭包使您可以从内部函数访问外部函数的作用域。在 JavaScript 中,每次创建函数时都会创建闭包。”
比如说
const getShowName = () => {const name = "fatfish" // name是由getShowName创建的局部变量return () => {console.log(name) // 使用父函数中声明的变量}
}const showName = getShowName()showName() // fatfish
作为一名前端开发,闭包在很多场景中都会用到,功能确实有点牛!!
场景使用
1.解决循环问题
for (var i = 0; i < 3; i++) {setTimeout(() => {console.log(i) // 我要打印什么?}, 1000 * i)
}
我们怎样才能让它打印0、1、2呢?这个问题我们就可以使用闭包来解决
for (var i = 0; i < 3; i++) {((n) => {setTimeout(() => {console.log(n) // 我该打印啥?}, 1000 * n)})(i)
}
当然,我们还有另一种更简单的方法,只需将var替换为let即可解决这个问题。
for (let i = 0; i < 3; i++) {setTimeout(() => {console.log(i) // 打印啥?}, 1000 * i)
}
2.记忆功能
利用闭包的特性,我们可以减少计算量,提高我们编写的程序的性能。
const memoize = (callback) => {const cache = new Map()return function (n) {if (cache.has(n)) { // 当它已经存在于缓存中时,结果将直接返回,我们不需要再次计算return cache.get(n)} else {const res = callback.call(this, n)cache.set(n, res) // 第一次计算后,结果将被缓存return res}}
}
const fibonacci = memoize(function fib (n) {if (n === 1) {return 1}if (n === 2 || n === 3) {return 2}return fib(n - 1) + fib(n - 2)
})console.log(fibonacci(1)) // 1
console.log(fibonacci(10)) // 68
console.log(fibonacci(10)) // 68 从缓存中拿到
3.封装私有变量和属性
很早以前,我们经常通过闭包来实现对私有变量的保护。我们只能通过getName和setName来获取和设置_name的值。这样我们就可以有效防止_name被恶意修改。
const createName = (name) => {let _name = namereturn {getName () {return _name},setName (name) {_name = name}}
}
const p = createName('fatfish')
p.getName() // fatfish
p.setName('medium')
p.getName() // medium
4.函数柯里化
什么是函数柯里化?
baidu:在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
const curry = (callback, ...args) => {return function (...innerArgs) {innerArgs = args.concat(innerArgs)if (innerArgs.length >= callback.length) {return callback.apply(this, innerArgs)} else {return curry(callback, innerArgs)}}
}const add = curry((a, b, c) => {return a + b + c
}, 1)
console.log(add(2, 3)) // 6