美文网首页
理解JavaScript纯函数

理解JavaScript纯函数

作者: 未路过 | 来源:发表于2022-10-11 23:22 被阅读0次

函数式编程是一种编程范式,主要是利用函数把运算过程封装起来,通过组合各种函数来计算结果。函数式编程意味着你可以在更短的时间内编写具有更少错误的代码。

1 纯函数定义

函数式编程中有一个非常重要的概念叫纯函数,JavaScript符合函数式编程的范式,所以也有纯函数的概念

  1. react开发中纯函数是被多次提及的;

  2. 比如react中组件就被要求像是一个纯函数(为什么是像,因为还有class组件),redux中有一个reducer的概念,也是要求必须是一个纯函数;

  3. 所以掌握纯函数对于理解很多框架的设计是非常有帮助的;

纯函数的定义:

1.确定的输入,一定会产生确定的输出;

2.函数在执行过程中,不能产生副作用;

那么这里又有一个概念,叫做副作用,什么又是副作用呢?

**副作用(side effect):在计算机f科学中,也引用了副作用的概念,表示在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响,比如修改了全局变量,修改参数或者改变外部的存储;

2 纯函数的案例

var names = ["abc", "cba", "nba", "dna"]

// slice只要给它传入一个start/end, 那么对于同一个数组来说, 它会给我们返回确定的值
// slice函数本身它是不会修改原来的数组
// slice -> this
// slice函数本身就是一个纯函数
// var newNames1 = names.slice(0, 3)
// console.log(newNames1)
// console.log(names)

// ["abc", "cba", "nba", "dna"]
// splice在执行时, 有修改掉调用的数组对象本身, 修改的这个操作就是产生的副作用
// splice不是一个纯函数
var newNames2 = names.splice(2)
console.log(newNames2)// ['nba', 'dna']
console.log(names)//(2) ['abc', 'cba']

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var newFruits = fruits.splice(2, 1, "Lemon", "Kiwi");
console.log(newFruits);//['Apple']
console.log(fruits);//['Banana', 'Orange', 'Lemon', 'Kiwi', 'Mango']

//splice() 方法向/从数组添加/删除项目,并返回删除的项目。

3 纯函数的优势

为什么纯函数在函数式编程中非常重要呢?

  1. 因为你可以安心的编写和安心的使用;

  2. 你在写的时候保证了函数的纯度,只是单纯实现自己的业务逻辑即可,不需要关心传入的内容是如何获得的或

者依赖其他的外部变量是否已经发生了修改;

  1. 你在用的时候,你确定你的输入内容不会被任意篡改,并且自己确定的输入,一定会有确定的输出;

4 JavaScript柯里化

在计算机科学中,柯里化(英语:Currying),又译为卡瑞化加里化

只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数;

这个过程就称之为柯里化;

5 柯里化的结构


function add(x, y, z){
  return x + y + z
}

var result = add(10, 20, 30)
console.log(result);
//对上面的函数进行柯里化
function sum1(x){
  return function(y){
    return function(z){
      return x + y + z
    }
  }
}

var result1 = sum1(10)(20)(30)

console.log(result1);

/* var sum2 = (x) => {
  return (y) => {
    return (z) => {
      return x + y + z
    }
  }
}


var result2 = sum2(10)(20)(30);
console.log(result2); */

//简化箭头函数 如果参数只有一个, ()可以省略
//step1

/* var sum2 = x => {
  return y => {
    return z => {
      return x + y + z
    }
  }
} */

//如果函数执行体只有一行代码, 那么{}也可以省略
// 强调: 并且在{}省略的前提下它会默认将这行代码的执行结果作为返回值
//step2
var sum2 = x => y => z => x + y + z;
    
  
var result2 = sum2(10)(20)(30);
console.log(result2);

6 为什么需要有柯里化

1.让函数的职责单一

  1. 在函数式编程中,我们其实往往希望一个函数处理的问题尽可能的单一,而不是将一大堆的处理过程交给一个

函数来处理;

  1. 那么我们是否就可以将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中再使用处理后的结

果;

  1. 比如上面的案例我们进行一个修改:传入的函数需要分别被进行如下处理

第一个参数 + 2

第二个参数 * 2

第三个参数 平方

function foo(x){
  x = x + 2;
  return function(y){
    y = y * 2;
    return function(z){
      z = z*z
      return x + y + z
    }
  }

2.复用参数逻辑

对一些逻辑做一个复用

  1. makeAdder函数要求我们传入一个count(并且如果我们需要的话,可以在这里对count进行一些修改);

  2. 在之后使用返回的函数时,我们不需要再继续传入count了;

// function sum(m, n) {
//   return m + n
// }

// // 假如在程序中,我们经常需要把5和另外一个数字进行相加
// console.log(sum(5, 10))
// console.log(sum(5, 14))
// console.log(sum(5, 1100))
// console.log(sum(5, 555))

function makeAdder(count) {
  count = count * count

  return function(num) {
    return count + num
  }
}

// var result = makeAdder(5)(10)
// console.log(result)
var adder5 = makeAdder(5)
adder5(10)
adder5(14)
adder5(1100)
adder5(555)

逻辑的复用案例

 function log(date, type, message){
  console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]:[${message}]`);
} 

// log(new Date(), "DEBUG", "查找到轮播图的bug")
// log(new Date(), "DEBUG", "查询菜单的bug")
// log(new Date(), "DEBUG", "查询数据的bug")

//// 柯里化的优化

var log = date => type => message =>{
  console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]:[${message}]`);
}
// 如果我现在打印的都是当前时间
var nowLog = log(new Date());
console.log(nowLog("Debug")("查找到轮播图的bug"));
console.log(nowLog("FEATURE")("查找到轮播图的bug"));

//如果都是"DEBUG"

var nowAndDebugLog = log(new Date())("DEBUG");
console.log(nowAndDebugLog("查询数据的bug"));
console.log(nowAndDebugLog("查询菜单的bug"));

7 js字符模板串

ES6中引入了模板字符串,让我们告别了使用大量'' 和 +来连接字符串了写法。

要创造一个模板字符串,只需要使用反引号``将字符串包起来,模板字符串中的变量用${变量名}替代即可


var a = 'o,';var b = 'd!'
console.log (`Hell${a}worl${b}`);
// Hello,world!

1、多行字符串

在模板字符串内,换行和空格是会保存并展示出来的

var a = 'o,';var b = 'd!'
console.log(`Hell${a}
worl${b}`);
/*
Hello,
world!
*/

2、嵌入表达式

var a = 1; b = 2;
console.log (`${a} + ${b} = ${a + b} `)
//1 + 2 = 3
1
2
3
3、调用函数

function string(){
return "Hello!";
}
console.log(`${string()} world!`);
//Hello! world!

8 柯里化函数的实现


function add(x, y, z){

  return x + y + z
}


/* function hyCurring(fn){
  
  var myRet = function(...arg){
    if (fn.length > arg.length){
      return  function(...arg1){
        if(fn.length > (arg.length + arg1.length)){
          return function(...arg2){
            if(fn.length > (arg.length + arg1.length + arg2.length)){
              return 1111
            }else{
              return fn(...arg, ...arg1, ...arg2)
            }
          }
        }else{
          return fn(...arg,...arg1)
        }
      }
      
    }else{
      return fn(...arg)
    }
     

  }
  return myRet
} */


function hyCurring(fn){
//fn.length 得到函数fn有几个参数
  function curried(...arg){
    // 判断当前已经接收的参数的个数, 可以参数本身需要接受的参数是否已经一致了
    // 1.当已经传入的参数 大于等于 需要的参数时, 就执行函数
    if (arg.length >= fn.length){
      return fn.apply(this, arg)
    }else{
      // 没有达到个数时, 需要返回一个新的函数, 继续来接收的参数
      return function(...arg2){
        // 接收到参数后, 需要递归调用curried来检查函数的个数是否达到
        return curried.apply(this, arg.concat(arg2))
      }
    }
     

  }
  return curried
}

var curryAdd = hyCurring(add);
console.log(curryAdd(10)(20)(30));
console.log(curryAdd(10, 20)(30));
console.log(curryAdd(10, 20, 30));

9 理解组合函数

组合(Compose)函数是在JavaScript开发过程中一种对函数的使用技巧、模式:

  1. 比如我们现在需要对某一个数据进行函数的调用,执行两个函数double和square,这两个函数是依次执行的;
  2. 那么如果每次我们都需要进行两个函数的调用,操作上就会显得重复;
  3. 那么是否可以将这两个函数组合起来,自动依次调用呢?
  4. 这个过程就是对函数的组合,我们称之为组合函数(Compose Function);
function double(num) {
  return num * 2
}

function square(num) {
  return num ** 2
}

var count = 10
var result = square(double(count))
console.log(result)

// 实现最简单的组合函数
function composeFn(m, n) {
  return function(count) {
    return n(m(count))
  }
}

var newFn = composeFn(double, square)
console.log(newFn(10))

10 通用的组合函数的实现


function double(m) {
  return m * 2
}

function square(n) {
  return n * n
}

function add(j){
  return j + 120
}

//var newFn = hyCompose(double, square, add)
var newFn = hyCompose()
console.log(newFn(10))//[10]


function hyCompose(...fns){
  var length = fns.length;
  for(var i = 0; i < length; i++){
    if(typeof fns[i] !== 'function'){
      throw new TypeError("Expected arguments are functions")
    }
  }
  function composed(...args){
    var result = length? fns[0].apply(this, args):args;
    for(var i = 1;  i < fns.length; i++){
      result = fns[i].call(this,result)
    }
    return result
  }
  return composed
}

相关文章

  • 5.纯函数

    理解JavaScript纯函数 函数式编程中有一个非常重要的概念叫纯函数,JavaScript符合函数式编程的范式...

  • 理解JavaScript纯函数

    函数式编程是一种编程范式,主要是利用函数把运算过程封装起来,通过组合各种函数来计算结果。函数式编程意味着你可以在更...

  • javascript函数,以及闭包的理解

    javascript函数,以及闭包的理解 深入理解javascript函数定义与函数作用域深入理解javascri...

  • JS纯函数 柯里化函数 组合函数

    1.纯函数(Pure Function) 函数式编程中有一个非常重要的概念叫做纯函数,javascript符合函数...

  • JavaScript - 纯函数

    纯函数,一个通常出现在函数式编程中的概念。 一. 纯函数的特点是什么? 1. 纯函数结果只依赖于参数,与函数外部变...

  • JavaScript 纯函数

    你可能听过一个术语叫纯函数,它是一个非常重要的概念,我们下面将来介绍它。 两项标准 纯函数必须满足两个条件: 对于...

  • 纯函数

    Function VS Procedures 这里的纯函数指的是在函数式编程里面的纯函数。要理解好纯函数这个概念,...

  • JavaScript函数、this以及闭包

    JavaScript笔记(三) 函数 理解函数 Javascript函数的参数与大多数其他语言中的函数的参数不同。...

  • JavaScript函数式编程之深入理解纯函数

    纯函数是函数式编程的基础,需要重点理解。 纯函数的概念: 纯函数是这样一种函数,即相同的输入,永远会得到相同的输出...

  • Javascript纯函数缓存

    前言 最近看了gitbook上的一本书,名叫《JS函数式编程指南》,看到了一个之前从未想到的小方法,做个笔记,记录...

网友评论

      本文标题:理解JavaScript纯函数

      本文链接:https://www.haomeiwen.com/subject/nrbxzrtx.html