典型的闭包
典型的闭包是一个函数A内声明并返回一个函数B供外部使用,函数B内用到了A内部的局部变量或者形参。外界对A函数内变量的引用导致A作用域不能被释放,构成一个闭包。
function Counter(n) {let num = 0function add(){num += nconsole.log(num)}return add}let addOne = Counter(1)addOne() //1addOne() //2

几个闭包
function Counter() {let num = 0return function() {num++console.log(num)}}let count1 = Counter()count1() //1count1() //2let count2 = Counter()count2() //1count2() //2
换一种写法
const sum = a => b => a + bconsole.log(sum(3)(4))
更宽泛的闭包
更宽泛的场景是函数B不一定直接返回,只要B能够再次被调用,都构成闭包。比如A返回的是一个对象,而函数B是对象的属性。或者函数B能在setTimeout延时结束时的触发。
返回一个对象
function Counter() {let num = 0return {add(){num++console.log(num)}}}let counter = Counter()counter.add()counter.add()
什么都不返回
function Counter() {let num = 0function add(){num ++console.log(num)}window.add = add}let counter = Counter()add()
setTimeout
function Counter() {let num = 0function add(){num ++console.log(num)}setTimeout(add, 1000)}let counter = Counter()
闭包的作用
- 用来暂存“当时”的状态;
2. 用来“封装”一些数据
封装数据/模块模式/IIFE
const cache = (() => {const store = {}return {get(key) {return store[key]},set(key, val) {store[key] = val},remove(key) {delete store[key]}}})()console.log(cache) //{get: ƒ, set: ƒ, remove: f}cache.set('name', '饥人谷')cache.get('name'); // '饥人谷'cache.remove('name')
暂存数据/高阶函数/Curry
const makeUrl = domain => path => `https://${domain}${path}`const makeJrgUrl = makeUrl('jirengu.com')const makdeXdmlUrl = makeUrl('xiedaimala.com')const url1 = makeJrgUrl ('/about')const url2 = makdeXdmlUrl ('/index')
相关面试题
题1:以下代码输出什么?如果想输出 0、1、2、3、4 需要怎样修改
for(var i=0; i<5; i++){setTimeout(function(){console.log('clock:' + i )}, 0)}
题2:以下代码输出什么
function Counter(n) {let num = 0function add(){num += nconsole.log(num)}return add}let counter1 = Counter(1)counter1()counter1()let counter2 = Counter(2)counter2()counter2()
题3:当点击li时输出什么?
<ul><li>1</li><li>2</li><li>3</li><li>4</li></ul><script>let $arrLi = document.querySelectorAll('li')for(var i=0; i<$arrLi.length; i++) {$arrLi[i].onclick = function() {console.log(i)}}</script>
题4:把函数 sum(a, b, c) 变成 sum(a)(b, c) 的形式。
function sum(a, b, c) {
return a + b + c
}
题5:补全代码,把函数fn(a, b, c) 的调用形式变成 fn(a)(b)(c) 的调用形式。 fn的参数个数不定。
function sum(a, b, c, d) {
return a + b + c + d
}
function curry(fn) {
//补全
}
let newSum = curry(sum)
newSum(1)(2)(3)(4)
答案
题1
//方法1
for(let i=0; i<5; i++) {
setTimeout(() => {
console.log('clock:' + i )
}, 0)
}
//方法2
for(var i=0; i<5; i++) {
((i) => {
setTimeout(() => {
console.log('clock:' + i )
}, 0)
})(i)
}
//方法3
for(var i=0; i<5; i++) {
setTimeout(((i) => () => {
console.log('clock:' + i )
})(i), 0)
}
题2
输出 1 2 2 4
题3
for(let i=0; i<$arrLi.length; i++) {
$arrLi[i].onclick = function() {
console.log(i)
}
}
for(var i=0; i<$arrLi.length; i++) {
((i) => {
$arrLi[i].onclick = function() {
console.log(i)
}
})(i)
}
for(let i=0; i<$arrLi.length; i++) {
$arrLi[i].onclick = ((i) => function() {
console.log(i)
})(i)
}
题4
function sum(a) {
return function(b, c) {
return a + b + c
}
}
const sum = a => (b, c) => a + b + c
题5
function sum(a, b, c, d) {
return a + b + c + d
}
function curry(fn) {
return function curried(...args) {
if(args.length >= fn.length) {
return fn(...args)
} else {
return function(...args2) {
return curried(...args.concat(args2))
}
}
}
}
let newSum = curry(sum)
newSum(1)(2)(3)(4)
newSum(1)(2,3)(4)
