关于javascript:JavaScript中的函数式编程

41次阅读

共计 2361 个字符,预计需要花费 6 分钟才能阅读完成。

函数式编程

函数式编程是一种编程范式,是一种构建计算机程序构造和元素的格调,它把计算看作是对数学函数的评估,防止了状态的变动和数据的可变,与函数式编程绝对的是命令式编程。咱们有这样一个需要,给数组的每个数字加一:

// 数组每个数字加一, 命令式编程
let arr = [1, 2, 3, 4];
let newArr = [];
for(let i = 0; i < arr.length; i++){newArr.push(arr[i] + 1);
}

console.log(newArr); // [2, 3, 4, 5]

这段代码后果没有问题,然而没法重用。咱们换一个思维,这外面蕴含的操作其实就两个,一个是遍历数组,一个是成员加一。咱们把这两个办法拆出来:

// 先拆加一进去
let add1 = x => x +1;

// 而后拆遍历办法进去,通过遍历返回一个操作后的新数组
// fn 是咱们须要对每个数组想进行的操作
let createArr = (arr, fn) => {const newArr = [];
  for(let i = 0; i < arr.length; i++){newArr.push(fn(arr[i]));
  }

  return newArr;
} 

// 用这两个办法来失去咱们冀望的后果
const arr = [1, 2, 3, 4];
const newArr = createArr(arr, add1);
console.log(newArr);  // [2, 3, 4, 5], 后果依然是对的

这样拆分后,如果咱们下次的需要是对数组每个元素乘以 2,咱们只须要写一个乘法的办法,而后复用之前的代码就行:

let multiply2 = x => x * 2;

// 调用之前的 createArr
const arr2 = [1, 2, 3, 4];
const newArr2 = createArr(arr2, multiply2);
console.log(newArr2);  // [2, 4, 6, 8], 后果是对的

事实上咱们的加一函数只能加一,也不好复用,它还能够持续拆:

// 先写一个通用加法,他接管第一个加数,返回一个办法
// 返回的这个办法接管第二个加数,第一个加数是下层办法的 a
// 这样当咱们须要计算 1 + 2 是,就是 add(1)(2)
let add = (a) => {return (b) => {return a + b;}
}

// 咱们也能够将返回的函数赋给一个变量,这个变量也就变成一个能特定加 a 的一个办法
let add1 = add(1);

let res = add1(4); 
console.log(res);  // 5

所以函数式编程就是将程序合成为一些更可重用、更牢靠且更易于了解的局部,而后将他们组合起来,造成一个更易推理的程序整体。

纯函数

纯函数是指一个函数,如果它的调用参数雷同,则永远返回雷同的后果。它不依赖于程序执行期间函数内部任何状态或数据的变动,只依赖于其输出参数。同时函数的运行也不扭转任何内部数据,它只通过它的返回值与内部通信。

上面这个函数就不是纯函数,因为函数外部须要的 discount 须要从内部获取:

let discount = 0.8;
const calPrice = price => price * discount;
let price = calPrice(200);  // 160

// 当 discount 变了,calPrice 传同样额参数,后果不一样,所以不纯
discount = 0.9;
price = calPrice(200);  // 180

要改为纯函数也很简略,将 discount 作为参数传递进去就行了

const calPrice = (price, discount) => price * discount;

纯函数能够保障代码的稳定性,因为雷同的输出永远会失去雷同后果。不纯的函数可能会带来副作用。

函数副作用

函数副作用是指调用函数时除了返回函数值之外,还对主调用函数产生附加的影响,比方批改全局变量或者内部变量,或者批改参数。这可能会带来难以查找的问题并升高代码的可读性。上面的 foo 就有副作用,当前面有其余中央须要应用 a,可能就会拿到一个被净化的值

let a = 5;
let foo = () => a = a * 10;
foo();
console.log(a); // 50

除了咱们本人写的函数有副作用外,一些原生 API 也可能有副作用,咱们写代码时应该留神:

咱们的指标是尽可能的缩小副作用,将函数写为纯函数,上面这个不纯的函数应用了new Date,每次运行后果不一样,是不纯的:

要给为纯函数能够将依赖注入进去,所谓依赖注入就是将不纯的局部提取进去作为参数,这样咱们能够让副作用代码集中在内部,远离外围代码,保障外围代码的稳定性

// 依赖注入
const foo = (d, log, something) => {const dt = d.toISOString();
  return log(`${dt}: ${something}`);
}

const something = 'log content';
const d = new Date();
const log = console.log.bind(console);
foo(d, log, something);

所以缩小副作用个别的办法就是:

1. 函数应用参数进行运算,不要批改参数
2. 函数外部不批改内部变量
3. 运算后果通过返回值返回给内部

可变性和不可变性

  • 可变性:指一个变量创立当前能够任意批改
  • 不可变性:指一个变量被创立后永远不会产生扭转,不可变性是函数式编程的外围概念

上面是一个可变的例子:

如果咱们肯定要批改这个参数,咱们应该将这个参数进行深拷贝后再操作,这样就不会批改参数了:

文章的最初,感激你破费贵重的工夫浏览本文,如果本文给了你一点点帮忙或者启发,请不要悭吝你的赞和 GitHub 小星星,你的反对是作者继续创作的能源。

作者博文 GitHub 我的项目地址:https://github.com/dennis-jiang/Front-End-Knowledges

正文完
 0