网站建设和管理经验,城乡和建设部建造师网站,注册一个电商平台需要多少钱,网站开发方向c语言介绍#xff1a;
函数式编程#xff08;FP#xff09;是一种编程范式#xff0c;这意味着一种基于一些原则来思考软件构建的方法#xff0c;比如 纯函数、不可变性、一等与高阶函数、函数组合、闭包、声明式编程、递归、引用透明性、柯里化 和 部分应用。
当这些原则有效…介绍
函数式编程FP是一种编程范式这意味着一种基于一些原则来思考软件构建的方法比如 纯函数、不可变性、一等与高阶函数、函数组合、闭包、声明式编程、递归、引用透明性、柯里化 和 部分应用。
当这些原则有效地应用到 JavaScript 中时可以使得代码更加模块化、可维护、健壮、易于理解、可测试并且能够优雅地处理复杂的问题。
这篇文章看起来可能有点长但不会那么理论化。
让我们开始逐一实验吧
1. 纯函数
两条规则
给定相同的输入总是返回相同的结果。不产生副作用。
用处 容易重构使代码更具灵活性和适应性。
例子 1
// 不纯的函数。
let a 4;
const multiplyNumbers (b) a * b;multiplyNumbers(3);
console.log(a); // 第一次调用1212
multiplyNumbers(3);
console.log(a); // 第二次调用3636// 修改了外部变量所以不是纯函数。// 纯函数版本。
const multiplyNumbers (x,y) x * y;multiplyNumbers(2, 3);6例子 2
// 不纯的函数。
addNumberarr (arr, num) {
arr.push(num);
};
const testArr [1,2,3];
addNumberarr(testArr, 4);console.log(testArr);[1, 2, 3, 4]// 修改了输入数组所以不是纯函数。// 上面的纯函数版本。
addNumberarr (arr, num) {
return [...arr, num];
};
const testArr [1,2,3];
addNumberarr(testArr, 4);[1, 2, 3, 4]JS 内置的纯函数
arr.reduce()
arr.map()
arr.filter()
arr.concat()
arr.slice()
arr.each()
arr.every()
... - 扩展语法JS 内置的非纯函数
arr.splice()
arr.push()
arr.sort()
Math.random()2. 不可变性
一旦创建就不能改变状态的对象。
一个简单的例子就是使用 slice 方法来帮助你轻松理解它的含义。
const arr [1,2,3,4];const slicedArray arr.slice(1,2);slicedArray[2]arr[1, 2, 3, 4]如果你看上面的例子slice 并没有改变原始数组 arr。而下面的例子则不同
const arr [1,2,3,4];arr.push(5);5arr[1, 2, 3, 4, 5]原始数组 arr 被修改了。这并不是说我们不应该使用 push但是在大多数情况下我们可以避免这种情况。一个简单的例子是
const arr [1,2,3,4];const newArr [...arr, 5];arr[1, 2, 3, 4]newArr[1, 2, 3, 4, 5]上面的所有都是简单例子可能不会造成任何问题。但是如果我们在整个文件中尽可能多地修改同一个对象就会带来许多问题。因为我们需要跟踪这个对象被修改了多少次以及以何种方式被修改。
为了解决这个问题我们需要避免修改对象。
3. 一等函数
一等函数是指把函数当作一等公民的概念意味着它们被视为常规变量或值。这让函数可以像字符串或数字等其他数据类型一样被操作和使用。这允许函数作为参数传递给其他函数从其他函数返回值以及被赋值给变量。JavaScript 支持这一点。
它打开了强大的编程技术的大门比如高阶函数、函数组合以及抽象的创建。
4. 高阶函数
一个函数可以接受另一个函数作为参数或者返回一个函数作为结果这样的函数被称为高阶函数。
返回一个函数的函数
const higherOrderFunc function() {return function() {return 12;}
}// 返回下面的函数所以它是高阶函数。
higherOrderFunc(); ƒ () {return 12;}higherOrderFunc()();12接受一个函数作为参数的函数
const testFunc function(x) {return x 12;
}// 接受函数作为参数。
const higherOrderFunc function(testFunc) {return testFunc(8);
}higherOrderFunc(testFunc);20例子 1
function calculate(operation, numbers) {return operation(numbers);
}function addition(numbers) {let sum 0;for (const number of numbers) {sumnumber;}return sum;
}function multiply(numbers) {let sum 1;for (const number of numbers) {sum*number;}return sum;
}const numbers [1,2,3,4,5];
console.log(calculate(addition, numbers));15console.log(calculate(multiply, numbers));120// calculate(multiply, numbers) - 传递函数作为参数时不加括号。高阶函数的好处
减少代码重复 单一职责
在 JavaScript 中函数可以接受原始类型或对象作为参数并返回相同类型称为一阶函数。
JS 内置的高阶函数有
arr.reduce(), arr.forEach(), arr.filter(), arr.map()
5. 函数组合
这是一种方法其中将一个函数的结果传给下一个函数。
const add (x, y) xy;const subtract (x) x-4;const multiply (x) x * 8;// add 的结果传给 subtract其结果再传给 multiply。
const result multiply(subtract(add(2, 3)));result;8看起来很清晰但如果我们要一个接一个地调用更多函数会怎么样呢让我们试试更干净的方法。
const compose (...functions) x functions.reduceRight((total, f) f(total), x);const add x x2;const subtract x x-1;const multiply x x * 8;compose(multiply, subtract, add)(2);24我们也可以使用 reduce 来实现
const pipe (...functions) x functions.reduce((total, f) f(total), x);const add x x2;const subtract x x-1;const multiply x x * 8;pipe(add, subtract, multiply)(2);24pipe - 从左到右执行。 compose - 从右到左执行。
6. 声明式编程
声明式 告诉 做什么
命令式 告诉 怎么做
例子 找出部门为 ‘justCode’ 的员工及其工资总和。
命令式风格
const employees [
{id: 1, name: james, dept: admin, salary: 10000},
{id: 1, name: Tom, dept: finance, salary: 10000},
{id: 1, name: peter, dept: justCode, salary: 12500},
{id: 1, name: tunner, dept: justCode, salary: 14500},
];const justCodeDept [];// 根据部门名称筛选员工。
for (let i0; iemployees.length; i) {if (employees[i].dept justCode) {justCodeDept.push(employees[i]);}
}// 计算 justCodeDept 员工的工资总和。
let summation 0;
for (j 0; jjustCodeDept.length; j) {summation summation justCodeDept[j].salary;
}console.log(summation);声明式风格
const employees [
{id: 1, name: james, dept: admin, salary: 10000},
{id: 1, name: Tom, dept: finance, salary: 10000},
{id: 1, name: peter, dept: justCode, salary: 12500},
{id: 1, name: tunner, dept: justCode, salary: 14500},
];console.log(employees.filter(item item.dept justCode).reduce(((previousValue, currentValue) previousValue currentValue.salary), 0));7. 柯里化
将接收多个参数的函数拆分成一系列函数每个函数只接收单个参数。
例子 1
通常我们写
function addition(x, y, z) {return x y z;
}addition(1, 2, 3);6柯里化版本
function addition(x) {return function addY(y) {return function addZ(z) {return x y z;}}
}addition(1)(2)(3);6使用箭头函数
addition (x) (y) (z) x y z;addition(1)(2)(3);6例子 2
function formWelcomNote(name) {name Hello ${name}, ;return function(location) {location Welcome to ${location},;return function(section) {return ${name}${location} Please visit ${section} section}}
}formWelcomNote(Yester)(VK Just Code Articles)(JS Articles);Hello Yester, Welcome to VK Just Code Articles, Please visit JS Articles section我们也可以这样写
formWelcomNote (name) {name Hello ${name}, ;return (location) {location Welcome to ${location},;return (section) {return ${name}${location} Please visit ${section} section}}
}formWelcomNote(Yester)(VK Just Code Articles)(JS Articles);Hello Yester, Welcome to VK Just Code Articles, Please visit JS Articles section例子 3
function calculation(fn) {switch (fn) {case add: return (a, b) a b;case sub: return (a, b) a - b;case mul: return (a, b) a * b;case div: return (a, b) a / b;}
}
console.log(calculation(mul)(4, 2));8. 部分应用
你为一个函数固定一定数量的参数并生成一个新的带有较少参数的函数。这个新函数可以在稍后的时间用剩下的参数来调用。部分应用有助于创建更加专业和可重用的函数。
例子
function add(a, b) {return a b;
}// 部分应用第一个参数
const add2 add.bind(null, 2);console.log(add2(5)); // 输出7 2 5
console.log(add2(8)); // 输出10 2 89. 引用透明性
JavaScript 中的一个表达式可以用它的值来替代这种特性叫做引用透明性。
const add (x, y) x y;const multiply (x) x * 4;// add (3, 4) 可以被替换为 7 —— 引用透明性。multiply(add(3, 4)); 28multiply(add(3, 4));28const arr [];
const add (x, y) {const addition x y;arr.push(addition);return addition;
}const multiply (x) x * 4;// 在这里我们不能用 7 替换 add(3, 4)因为它会影响程序逻辑。
multiply(add(3, 4));28multiply(add(3, 4));2810. 闭包
闭包让你可以从内部函数访问外部函数的作用域。
function outer() {const name test;function inner() {// name 从外部函数可以访问到内部函数中console.log(name);}inner();
}
outer(); testfunction outerAdd(x) {return function(y) {return x y;};
}const outer12 outerAdd(12); // x 为 12.
const outer14 outerAdd(14); // x 为 14.const outer12Result outer12(12); // y 为 12.
console.log(outer12Result);24const outer14Result outer14(14); // y 为 14.
console.log(outer14Result);28或者你也可以像下面这样使用箭头函数
outerAdd x y x y;const outer12 outerAdd(12);
const outer14 outerAdd(14);const outer12Result outer12(12);
console.log(outer12Result);24const outer14Result outer14(14);
console.log(outer14Result);28使用闭包的计数器示例
function outer() {let counter 0;return function inner() {counter 1;return counter;}
}
const out outer();console.log(out());
console.log(out());
console.log(out()); 12311. 递归
递归是一种编程技巧在其中函数通过自我调用来解决问题。
例子
function factorial(n) {if (n 0 || n 1) {return 1;} else {return n * factorial(n - 1);}
}console.log(factorial(5)); // 输出120 5 * 4 * 3 * 2 * 1
console.log(factorial(0)); // 输出1 按定义在这个例子中factorial 函数计算给定数 n 的阶乘。它使用了 n 0 和 n 1 的基本情况阶乘定义为 1。对于其它任何值的 n函数递归地调用自身并将结果乘以 n。
当你调用 factorial(5) 时递归调用序列如下所示
factorial(5)- 5 * factorial(4)- 4 * factorial(3)- 3 * factorial(2)- 2 * factorial(1)- 1- 2 * 1 2- 3 * 2 6- 4 * 6 24- 5 * 24 120如果有任何概念上的例子需要补充请随时评论。
希望通过今天这篇文章让你对JS中的函数式编程有了更好的理解。并且可以在日常的开发过程中进行灵活应用以提高开发效率。