函数式编程范式:高阶函数和闭包

目录

如果有小伙伴想要回顾之前的知识的话,点击下面的链接查看之前所有的学习栏目👇:
《大前端学习专栏:目录》

高阶函数

函数套着函数的现象,我们称外层函数是一个高阶函数。React中的高阶组件,其本质就是一个高阶函数。

函数作为参数

函数可以作为另一个函数的参数,这样可以使外层的函数可以更加灵活。
以下是两个将函数作为参数的实例,分别模拟了forEachfilter

//forEach
function forEach(list, fn) {
  for (let index = 0; index < list.length; index++) {
    const element = list[index];
    fn(element);
  }
}

//测试
let list = [1, 2, 3];
forEach(list, (item) => console.log(item)); //1 2 3

filter

//filter
function filter(list, fn) {
  let newList = [];
  for (let index = 0; index < list.length; index++) {
    const element = list[index];
    if (fn(element)) {
      newList.push(element);
    }
  }
  return newList;
}

//测试
let list = [1, 2, 3];
let newList = filter(list, (item) => item === 1);
console.log(newList); // [1]

将参数变成函数这样写的好处在哪里?
将函数作为参数一大好处就是可以将一部分逻辑抽离出去,不必关注这部分的具体实现,方便各个模块解耦。

函数作为另一个函数的返回值

其本质是让一个函数去生成另外一个函数,使返回的函数拥有更强大的功能。
以下是一个基础的示例:

function makeFn() {
  return function () {
    console.log('hello');
  };
}

let fn = makeFn();
fn();
// makeFn()();  也可以这么调用

在Vue中,有一个API是$once,表示监听一个自定义事件,但是只触发一次。一旦触发之后,监听器就会被移除。我们这里使用高阶函数来模拟一下$once

//无论点击几次都只能支付一次
function $once(fn) {
  let done = false;
  return function (...args) {
    if (done) return;
    done = true;
    return fn.apply(this, args);
  };
}

const pay = $once(function (money) {
  console.log(`我支付了${money}`);
});

pay(5); // 我支付了5
pay(5); //
pay(5); //

闭包

闭包(Closure):函数和其周围的状态(词法环境)的引用捆绑在一次形成闭包结构。
闭包结构可以在另一个作用域中调用一个函数的内部函数,并访问到内部函数作用域中的成员。
以下是一个简单的闭包结构:

function makeFn(){
	let msg = "hello world";
	return function(){
		console.log(msg);
	}
}

let fn = makeFn();
fn(); // hello world

以上示例中,内部函数引用了外部函数的msg变量,导致外部函数调用完毕之后作用域无法释放,被内部函数所牵引,形成了一个闭包结构。

闭包的本质

函数在执行的时候会放到一个执行栈中,当函数执行完毕后会从执行栈中被移除,但是堆上的作用域成员因为被外部引用无法释放,因此内部函数依然可以访问到外部函数的成员。

闭包在开发中的应用

在Vue2.0源码中使用了很多的闭包技巧来保存变量,以下是Vue2.0源码中缓存函数结果的实现:

export function cached<F: Function> (fn: F): F {
  const cache = Object.create(null)
  return (function cachedFn (str: string) {
    const hit = cache[str]
    return hit || (cache[str] = fn(str))
  }: any)
}

内部函数cachedFn引用外部函数的局部变量cache,形成了一个闭包结构。

Vue2.0源码中定义响应式对象:

export function defineReactive(
  obj: Object,
  key: string,
  val: any
) {
  const dep = new Dep();

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    //访问该值时,依赖收集
    get: function reactiveGetter() {
	   dep.depend();
	   return val;
    },
    //设置该值时,派发更新
    set: function reactiveSetter(newVal) {
      val = newVal;
      dep.notify();
    },
  });
}

内部函数getset引用了外部函数的valdep,形成了一个闭包结构,便于在之后的逻辑中重用这两个变量。

由此可见,使用闭包的好处是可以重用变量,节省多余代码。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习的前端小黄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值