JavaScript 函数式编程

发布于 2023-01-05 12:42:54 字数 7713 浏览 113 评论 0

前置知识

  • JavaScript 基础
  • JavaScript 面向对象

函数式编程含义

函数式编程是一种强调以函数使用为主的软件开发风格 ,也是一种范式。

某些函数式编程语言 Haskell、lisp、Scheme 等。

JavaScript 中函数式编程

数学中函数

f(x) = y;

JavaScript 中的函数

   let factor = 3;
   let totalNum = num=>factor*num;
   console.log( totalNum(3) );

对比两种函数,基于数学函数 来修复 JavaScript 函数

   let totalNum = (num,factor)=>factor*num;
   console.log( totalNum(3,3) );

JavaScript 是多范式编程语言,但是函数作为一等公民,函数式编程具有天然优势。

函数式编程中涉及到的概念

纯函数

函数式编程基于纯函数

纯函数是对给定的输入返还相同输出的函数;例如

let double = value=>value*2;

纯函数意义

纯函数可以产生可测试的代码

1、不依赖外部环境计算,不会产生副作用,提高函数的复用性。

test('double(2) 等于 4', () => {
  expect(double(2)).toBe(4);
})

2、可读性更强 ,JavaScript 函数不管是否是纯函数 都会有一个语义化的名称,更便于阅读。

3、可以组装成复杂任务的可能性。符合模块化概念及单一职责原则。

高阶函数

高阶函数定义

高阶函数:以函数作为输入或者输出的函数被称为高阶函数(Higher-Order Function)。

高阶函数的抽象

一般高阶函数用于抽象通用问题,简而言之,高阶函数就是定义抽象。

命令式循环(注重 如何 做,注重过程);

let arr = [1,2,3];
for(let i=0;i<arr.length;i++){
    console.log(arr[i]);
}

通过高阶函数抽象过程,声明式编程(注重做 什么,注重结果);

const forEach = function(arr,fn){
    for(let i=0;i<arr.length;i++){
        fn(arr[i]);
    }
}
let arr = [1,2,3];
forEach(arr,(item)=>{
    console.log(item);
})

上面通过高阶函数 forEach 来抽象循环 如何 做的逻辑,直接关注 做 什么

高阶函数的缓存特性

主要是利用函数的闭包

once 高阶函数

const once = (fn)=>{
    let done = false;
    return function(){
        if(!done){
            fn.apply(this,fn);
        }else{
            console.log("this fn is already execute");
        }
        done = true;
    }
}

function test(){
    console.log("test...");
}
let myfn =  once(test);
myfn();
myfn();

柯里化

什么是柯里化?

柯里化是把一个多参数函数转化成一个嵌套的一元函数的过程;

如下二元函数

let fn = (x,y)=>x+y;

柯里化函数

const curry = function(fn){
    return function(x){
        return function(y){
            return fn(x,y);
        }
    }
}
let myfn = curry(fn);
console.log( myfn(1)(2) );

多参数函数柯里化

// 多参数柯里化;
    const curry = function(fn){
        return function curriedFn(...args){
            if(args.length<fn.length){
                return function(){
                    return curriedFn(...args.concat([...arguments]));
                }
            }
           return fn(...args);
        }
    }
    const fn = (x,y,z,a)=>x+y+z+a;
    const myfn = curry(fn);
    // console.log(myfn(1)(2));
    console.log(myfn(1)(2)(3)(1));

柯里化意义

  • 让纯函数更 纯,每次接受一个参数,松散解耦
  • 某些语言及特定环境下只能接受一个参数
  • 惰性执行

组合(composition)和管道(pipe)

组合(composition)

组合函数:无需创建新的函数,通过基础函数解决眼前问题。

组合高阶函数 map 及 filter;

  • map 高阶函数
  • 组合 map 及 filter 来使用

compose 组合

可以封装组合函数来实现函数执行

2 个函数组合

function afn(a){
    return a*2;
}
function bfn(b){
    return b*3;
}
const compose = (a,b)=>c=>a(b(c));
let myfn =  compose(afn,bfn);
console.log( myfn(2));

多函数组合

const compose = (...fns)=>val=>fns.reverse().reduce((acc,fn)=>fn(acc),val);

管道(pipe)

compose 执行是从右到左,pipe 是从左至右的执行。函数如下:

const pipe = (...fns)=>val=>fns.reduce((acc,fn)=>fn(acc),val);

​ 管道、组合 取舍 :管道及组合最大区别在于执行顺序的不同,数据流向不同,达到目的是类似的。所以无优 劣之分,保持团队风格统一就好了。

组合及管道的意义 把很多小函数组合起来完成更复杂的逻辑。

Pointfree 编程风格

概念:不适用处理的值,只合成运算过程,也就是无值风格。

获取所有的句号

const sentenceNum = str=>str.match(/。/g);
let str = "大家好,我是中国人。我爱中国。我们同住地球村。";
console.log(sentenceNum(str));

统计长度

const countFn = arr=>arr.length;

判断奇偶

const oddOrEven = num=>num%2===0?"偶数":"奇数";

pointfree 风格组合函数使用:找到句号统计长度最后判断奇偶数

let str = "大家好,我是中国人。我爱中国。我们同住地球村。";
const myfn = compose(oddOrEven,countFn,sentenceNum);
console.log(myfn(str));

JavaScript 函数式编程库

  • lodash.js 、ramda.js 、Underscore.js
  • 通过 ramda.js 实现数据筛选功能;

函数式编程在 redux 中应用

Redux 整体是通过函数式 编程思维实现的;

createStore 简单实现

const createStore = (reducer, initialState) => {
    const store = {};
    let  currentState = initialState;
    const  listeners = [];
    const getState = () => currentState;
    const subscribe = (listener) => {
        listeners.push(listener);
    };
    const dispatch = (action) => {
        // store.state = deepFreeze(reducer(store.state, action) );
        currentState = reducer(currentState, action);
        listeners.forEach(listener => listener());
    };
    return {
        getState,
        subscribe,
        dispatch
    };
};

export {createStore};

状态管理调用

import {createStore} from "../MyRedux.js";
// import { createStore } from 'redux';
function Counter(state={count:0},action) {
    switch (action.type) {
        case "ADD_COUNT":
            return {count:state.count + 1}
            break;
        case "REDUCE_COUNT":
            return {count:state.count - 1}
            break;
        default:
            return state;
            break;
    }
}
var store = createStore(Counter);


btn.onclick = function(){
    // console.log(store);
    store.dispatch({type:"ADD_COUNT"});
}

store.subscribe(() => {
    // console.log(store)
    renderDom()
})

function renderDom(){
  let mydiv =   document.querySelector(".countDiv");
  if(typeof store.getState() !== "undefined"){
    mydiv.innerHTML = store.getState().count;
  }
}

函子

容器函子 Functor

函子是函数式编程里面最重要的数据类型,也是基本的运算单位和功能单位。

定义自己的Functor。

class Container{
    constructor(value){
        this._value = value;
    }
    static of(val){
        return new Container(val);
    }
}
let res = Container.of(1);
console.log(res);

通过 map 修改 Functor 值

class Container{
    constructor(value){
        this._value = value;
    }
    static of(val){
        return new Container(val);
    }
    map(fn){
        return Container.of(fn(this._value));
    }
}
let res = Container.of(1);
// console.log(res);
let reslut =  res.map(item=>{
    // console.log(item);
   return item+3
}).map(item=>{
    return "最终结果是" + item;
})

MeBe 函子

处理空值的函子

class Mabe{
    constructor(val){
        this._value = val;
    }
    static of(val){
        return new Mabe(val);
    }
    isNoThing(){
        return (this._value===null || this._value=== undefined);
    }
    map(fn){
        return this.isNoThing()?Mabe.of(null):Mabe.of(fn(this._value));
    }
}

Either 函子

class Either extends Functor{
    constructor(left,rigth){
        super();
        this.left = left;
        this.right = rigth;
    }
    map(f){
        return this.right?Either.of(this.left, f(this.right)) :
      Either.of(f(this.left), this.right);
    }
    static of(left, right){
        return new Either(left, right);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

日久见人心

暂无简介

文章
评论
26 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

更多

友情链接

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文