闭包

60 阅读2分钟

闭包的定义

闭包是指那些能够访问自由变量的函数

自由变量是指在函数中使用的,但既不是函数参数也不是函数局部变量的变量

  1. 从理论角度: 所有的函数都有可能是闭包。函数中去访问全局变量就相当于去访问自由变量
  2. 从实践角度:
    1. 即使创建它的上下文已经被销毁了,它仍然存在。(内部函数从父函数中返回)
    2. 代码中引用了自由变量

应用场景

  1. 柯里化函数 避免频繁调用具有相同参数的函数,同时能够轻松的复用 其实就是封装一个高阶函数
    function getArea(width,height){
        return width * height
    }
    const area1 = getArea(10,20)
    const area2 = getArea(10,30)
    const area3 = getArea(10,40)
    const area4 = getArea(10,50)

    // 以上函数调用,10是固定的宽度,那我们就可以简写成一个柯里化函数

    function getArea(width){
        return height=>width*height
    }
    const getTenWidthArea = getArea(10)
    const area1 = getTenWidthArea(20)
    const area2 = getTenWidthArea(30)
    const area3 = getTenWidthArea(40)
    const area4 = getTenWidthArea(50)
  1. 使用闭包实现私有的方法/变量

模块: 现代化的打包方式,最终就是每个模块都是相互独立的

    function funcOne(i){
        function funcTwo(){
            console.log('数字'+i)
        }
        return funcTwo
    }
    const fa = functionOne(110)
    const fb = functionOne(120)
    const fc = functionOne(130)
  1. 匿名自执行函数
    var funcOne = (function(){
        var num = 0;
        return function(){
            num++
            return num
        }
    })()

    console.log(funcOne()) // 1
    console.log(funcOne()) // 2
    console.log(funcOne()) // 3
  1. 缓存一些结果 外部函数中创建一个数组,闭包函数可以获取或者修改这个数组的值,延长变量的生命周期。
    function funParent(){
        let memo = []
        function funcTwo(){
            memo.push(i)
            console.log(memo.join('.'))
        }
        return funcTwo
    }
    const fn = funParent()
    fn(1)
    fn(2)

总结

  • 创建私有变量
  • 延长变量的生命周期

代码题

//实现一个compose函数,用法如下
function fn1(x){
    return x+1
}
function fn2(x){
    return x+2
}
function fn3(x){
    return x+3
}
function fn4(x){
    return x+4
}
function compose(...fnArr){
    return function(num){
        return fnArr.reduce((pre,cur)=>cur(pre),num)
    }
}
const a = compose(fn1, fn2, fn3, fn4)
console.log(a(1))
function currying(fn,...args){
    const originalArgLength = fn.length
    let params = args
    const resFn = (...innerArgs) =>{
        params = params.concat(innerArgs)
        if(params.length === originalArgLength) {
            return fn(...params)
        }else{
            return resFn
        }
    }
    return resFn
}
const add = (a,b,c)=>a+b+c
const a1 = currying(add,1)
const a2 = a1(2)
console.log(a2(3))

// 题目需求
let middleware = []
middleware.push((next)=>{
    console.log(1)
    next()
    console.log(1.1)
})
middleware.push((next)=>{
    console.log(2)
    next()
    console.log(2.1)
})
middleware.push((next)=>{
    console.log(3)
    next()
    console.log(3.1)
})
let fn = compose(middleware)
fn()
// 要求实现的打印顺序
/*
1
2
3
3.1
2.1
1.1
*/
// 实现compose函数
function compose(middlewares){
    const copyMiddlewares = [...middlewares]
    let index = 0
    let fn = ()=>{
        if(index>=copyMiddlewares.length){
            return
        }
        let middleware = copyMiddlewares[index]
        index++
        return middleware(fn)
    }
    return fn
}