likes
comments
collection
share

初步浅尝一下JS中的函数柯里化

作者站长头像
站长
· 阅读数 19

1. 概念说明

函数柯里化(Currying)是一种将接受多个参数的函数转换成一系列接受单个参数的函数的技术。这个概念是由数学家Haskell Curry命名的,他是逻辑学、计算机科学和数学领域的重要人物之一。

在JavaScript中,函数柯里化可以通过将一个函数转换成一个接受单个参数的函数序列来实现。每个函数都返回一个新函数,该函数接受下一个参数,并在最后一个函数中返回结果。

下面是一个简单的例子来说明函数柯里化的概念:

function add(a) {
  return function(b) {
    return a + b;
  };
}

// 使用柯里化函数
const add5 = add(5);
console.log(add5(3)); // 输出: 8

在上面的例子中,add 函数接受一个参数 a,并返回一个匿名函数,该匿名函数接受参数 b,并返回 a + b 的结果。

通过调用 add(5),我们获得了一个新的函数 add5,该函数将 5 作为第一个参数。然后,我们调用 add5(3),它接受参数 3,并返回结果 8。

通过函数柯里化,我们可以将接受多个参数的函数转换为接受单个参数的函数序列,这样可以更方便地进行函数复用和部分应用。它还能够帮助我们创建更具通用性和可组合性的函数,使代码更加模块化和可读性更强。

需要注意的是,JavaScript并非纯粹的函数式编程语言,而函数柯里化只是一种技术,可以根据需要在代码中使用。许多JavaScript库和框架,如lodash和Ramda,提供了方便的函数柯里化的工具函数来简化开发过程。

2. 具体应用:Pinia插件(Vue插件也差不多的原理)

接下来,我再给出一个具体应用在Vue3.0 + Pinia项目中的函数柯里化的例子:

localStoragePlugin.ts↓

import { toRaw } from "vue"; // 引入toRaw
import { PiniaPluginContext } from "pinia"; // 引入pinia

type Options = {
  key?: string;
};

const __piniaKey__: string = "non_hana"; // 默认key值

// 定义存储本地空间的函数
const setStorage = (key: string, value: any) => {
  localStorage.setItem(key, JSON.stringify(value));
};

// 定义读取本地空间的函数
const getStorage = (key: string) => {
  return localStorage.getItem(key)
    ? JSON.parse(localStorage.getItem(key) as string)
    : {};
};

// 定义pinia插件函数
const piniaPlugin = (options: Options) => {
  // 此处return是函数科里化的写法,经常用于解构函数参数,也就是参数降维
  // 当store.use(piniaPlugin())时,会自动传入context,而我们此处需要自定义传入的options,所以需要返回一个函数来接收这个自动传入的context
  // ps:写插件的时候很常用!因为写插件的时候都是通过XXX.use这样的形式来引入插件,这样子通常会自动传入一些参数,我们需要自定义传入的参数,就需要用到科里化的写法
  return (context: PiniaPluginContext) => {
    const { store } = context; // 将context解构出来
    // 调用getStorage读取存在本地的已有数据
    const data = getStorage(`${options?.key ?? __piniaKey__}-${store.$id}`); // 读取本地空间的数据
    store.$subscribe(() => {
      console.log("changed");
      setStorage(
        `${options?.key ?? __piniaKey__}-${store.$id}`,
        toRaw(store.$state)
      );
    });
    // 返回值覆盖pinia state里面的原始值
    return {
      ...data,
    };
  };
};

// 导出pinia插件
export default piniaPlugin;

main.ts↓

import { createApp } from "vue";
import App from "./App.vue";
import { createPinia } from "pinia"; // 引入pinia
import piniaPlugin from "./store/localStoragePlugin"; // 引入自定义的pinia插件

export const app = createApp(App);
app.use(ElementPlus);

// 用store接收createPinia()返回的对象
const store = createPinia();
// 将piniaPlugin注册到store上
store.use(
  piniaPlugin({
    key: "pinia",
  })
);

// 将store挂载到app上,相当于一个插件
app.use(store);

app.mount("#app");

在这个例子中,我是自己写了一个能够将Pinia中的值保存在本地的一个插件。当要在Pinia上面注册自己写的这个插件的时候需要使用use这个api,而且当使用这个api的时候,pinia会自动传入一个参数context: PiniaPluginContext,而我们在这边希望自己定义一个传入的参数key,因此我将自动传入的这个参数写到下面的return函数的参数内部,自己传的参数写在原本的函数参数内部,这样子将参数拆分成两个部分,互不干扰。

转载自:https://juejin.cn/post/7241114001324605495
评论
请登录