什么是閉包?
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