Aimee

personal blog

欢迎来到我的个人站~


闭包

你了解闭包?你平常用闭包的场景有哪些?

闭包的定义?

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

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

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

应用场景

    1. 柯里化函数 避免频繁调用具有相同参数的函数,同时能够轻松的复用 其实就是封装一个高阶函数
function getArea(width, height) {
    return width * height;
}

const area1 = getArea(10, 29);
const area2 = getArea(10, 20);
// 第一个参数保持不变,可以用柯里化函数

function getArea(width) {
    return height => {
        return width * height;
    }
}

const getTenWidthArea = getArea(10);
const area1 = getTenWidthArea(29);
    1. 使用闭包实现私有方法/变量
  • 模块
  • 现代化的打包方式,最终就是每个模块的代码都是相互独立的

    1. 匿名的自执行函数
      var fnOne = (fuction() {
        var num = 0;
        return function() {
         num++;
         return num;
        }
      })();
      
    1. 缓存一些结果

外部函数中创建一个数组,闭包函数可以获取或者修改这个数组的值,延长了变量的生命周期

function funParent() {
    let meno = [];

    function funOne(i) {
        meno.push(i);
        console.log(meno);
    }

    return funOne;
}

总结

  • 创建自由变量
  • 延长变量的生命周期

代码题

// 实现一个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;
}

const a1 = compose(fn1, fn2, fn3, fn4);
console.log(a1(1)); // 1+2+3+4+1 = 11

// 解答
function compose() {
 const argsArr = [...arguments];
 return (x) => {
     return argsArr.reduce((pre, cur) => cur(pre), x);
 }
}
// 柯里化
function currying(fn, ...args) {
    const originFnLength = fn.length;
    let allArgs = [...args];
    const resFn = (...fnArgs) => {
        allArgs = [...allArgs, ...fnArgs];
        if(originFnLength === allArgs.length) {
           return fn(...allArgs);
        } else {
            return resFn;
        }
    }

    return resFn;
}

const add = (a, b, c) => a+b+c;

const a1 = currying(add, 1);
const a2 = a1(2);
const a3 = a2(3);
/**
题目需求,实现koa compose
*/
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(); 

function compose(middleware) {
    const copyMiddleware = [...middleware];
    let index = 0;
    const fn = () => {
        if(index >= copyMiddleware.length) {
            return;
        }
        const curMiddleware = copyMiddleware[index];
        index++;
        return curMiddleware(fn);
    }

    return fn;
}
/*
1
2
3
3.1
2.1
1.2