tiantingrui / daily-harvest

记录每日收获
MIT License
2 stars 0 forks source link

你了解闭包吗?你平常用闭包的应用场景有哪些? #26

Open tiantingrui opened 2 years ago

tiantingrui commented 2 years ago

闭包的定义

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

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

  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)

function getArea(width) {
  return height => {
    return width * height
  }
}
// 确定 width 这个变量不经常变化去缓存下来
const getTenWidthArea = getArea(10)

const area1 = getTenWidthArea(20)
const area2 = getTenWidthArea(30)
const area3 = getTenWidthArea(40)
const area4 = getTenWidthArea(50)

2. 使用闭包实现私有方法/变量

模块

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

function one(i) {
  function two() {
    console.log('数字' + i)
  }
  return two
}

const fa = one(110)
const fb = one(111)
const fc = one(112)

fa();
fb();
fc();

3. 匿名自执行函数

var one = function() {
  var num = 0
  return function() {
    num++
    return num
  }
}()

console.log(one()) // 1
console.log(one()) // 2
console.log(one()) // 3

4. 缓存一些结果

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

function parent() {
  let memo = []

  function child(i) {
    memo.push(i)
    console.log(memo.join(','))
  }

  return child
}

const fn = parent()
fn(1)
fn(2)

总结

tiantingrui commented 2 years ago

实现一个 compose 函数

// 实现一个 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 a = compose(fn1, fn2, fn3, fn4);
console.log(a(1)); // 1 + 4 + 3 + 2 + 1

// 解答
// function compose() {
//   const argFnList = [...arguments];

//   return (num) => {
//     return argFnList.reduce((pre, cur) => {
//       console.log("pre", pre);
//       console.log("cur", cur);
//       return cur(pre);
//     }, num);
//   };
// }

function compose() {
  const argFnList = [...arguments];

  return (num) => argFnList.reduce((pre, cur) => cur(pre), num);
}
tiantingrui commented 2 years ago

实现一个柯里化函数

function currying(fn, ...args) {
  const oldFnArgLen = fn.length;
  let allArgs = [...args];

  const resFn = (...newArgs) => {
    allArgs = [...allArgs, ...newArgs];

    if (allArgs.length === oldFnArgLen) {
      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);
console.log(a2(3)); // 6
tiantingrui commented 2 years ago

Koa-compose

// 题目需求 koa -> 洋葱模型

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;

  const fn = () => {
    if (index >= copyMiddlewares.length) {
      return;
    }

    const middleware = copyMiddlewares[index];
    index++;
    // fn 就是 next
    return middleware(fn);
  };

  return fn;
}