函数式编程是一种重要的编程范式。它将程序构建视为一系列函数的组合,强调通过表达式和声明来解决问题,而不是详细描述执行步骤。这种编程方式与传统的命令式编程有很大不同。
编程范式主要分为命令式、声明式和函数式。
命令式编程关注“如何做”,通过编写详细的指令步骤让计算机执行。它常常涉及大量具体细节。
声明式编程关注“做什么”,通过表达式声明目标,而不是一步步的指示。SQL查询就是典型例子,我们只声明需要什么数据,而不指定数据库具体如何查询。
函数式编程属于声明式范式的一种,它以函数为基本构建单元,强调无状态和不可变数据。
纯函数是函数式编程的基础。纯函数指不依赖外部状态、不改变外部数据,对于相同输入总是返回相同输出的函数。这种特性让代码更易于测试和推理,也便于并行处理。
不可变性要求数据一旦创建就不能修改。任何更改都需要通过创建新数据来实现。这种做法避免了共享状态带来的问题,提高了代码在并发环境下的可靠性。
高阶函数是指能够接收函数作为参数,或者能够返回函数的函数。JavaScript中的map、filter、reduce等都是高阶函数的例子。它们提升了代码的复用性和可读性。
纯函数的定义很明确:相同输入总是产生相同输出,且不会修改外部状态。
这是一个纯函数例子:
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 总是输出5
这是一个非纯函数例子:
let count = 0;
function increment() {
return ++count;
}
console.log(increment()); // 输出1,但每次调用结果可能不同
JavaScript数组方法中,slice是纯函数,而splice不是:
let arr = [1,2,3,4,5,6,7]
arr.slice(0,2) // 返回[1,2],原数组不变
arr.slice(0,2) // 仍然返回[1,2]
arr.splice(0,2) // 返回[1,2],但原数组变为[3,4,5,6,7]
arr.splice(0,2) // 返回[3,4],原数组再次改变
纯函数有三大优势:易于测试、支持并行处理、可缓存结果。缓存机制可以这样实现:
function getArea(r) {
return Math.PI * r * r;
}
function memoize(fn) {
let cache = {};
return function() {
let key = JSON.stringify(arguments);
cache[key] = cache[key] || fn.apply(fn, arguments);
return cache[key];
};
}
const getAreaMemory = memoize(getArea);
console.log(getAreaMemory(2)); // 计算并缓存结果
console.log(getAreaMemory(2)); // 直接返回缓存结果
不可变性意味着数据创建后不能被修改。任何变更都需要创建新数据副本。
看这个有副作用的例子:
let min = 20;
function compare(num) {
return num >= min;
}
这个函数不是纯函数,因为它依赖外部变量min。有两种解决方案:
第一种是将变量放在函数内部:
function compare(num) {
let min = 20;
return num >= min;
}
第二种是使用柯里化(闭包):
function compare(min) {
return function(num) {
return num >= min;
};
}
高阶函数可以接受函数作为参数,或返回函数作为结果。JavaScript中数组的map、filter、reduce等都是高阶函数。
实现一个简单的map函数:
function map(array, fn) {
const result = [];
for (let i = 0; i < array.length; i++) {
result.push(fn(array[i]));
}
return result;
}
const numbers = [1, 2, 3, 4, 5];
const doubled = map(numbers, (x) => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
柯里化是将多参数函数转换为一系列单参数函数的过程:
const add = a => b => a + b;
const add5 = add(5);
console.log(add5(3)); // 8
console.log(add5(10)); // 15
手动实现柯里化函数:
const curry = function(func) {
return function curriedFn(...args) {
if (args.length < func.length) {
return function(...args2) {
return curriedFn(...args.concat(args2));
};
} else {
return func(...args);
}
};
};
数组方法是函数式编程的常见应用:
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(n => n * 2);
console.log(doubledNumbers); // [2, 4, 6, 8, 10]
const users = [
{ name: 'John', age: 34 },
{ name: 'Amy', age: 20 },
{ name: 'camperCat', age: 10 }
];
const usersUnder30 = users.filter(user => user.age < 30);
console.log(usersUnder30); // 20岁以下的用户
函数组合可以将多个小函数组合成更复杂的功能:
const reverse = value => value.reverse();
const toUpper = value => value.toUpperCase();
const first = value => value[0];
function compose(...fns) {
return function(value) {
return fns.reverse().reduce((acc, fn) => {
return fn(acc);
}, value);
};
}
const getLastInitial = compose(toUpper, first, reverse);
console.log(getLastInitial(['one', 'two', 'three'])); // THREE
函数式编程的优点很明显:更好地管理状态,因为尽可能减少状态变化;更简单的代码复用,由于函数无副作用;更优雅的函数组合,便于构建复杂系统;同时还能减少代码量,提高可维护性。
但它也有缺点:性能可能不如命令式编程,因为往往需要创建新对象;内存占用更高,因为不可变性需要频繁创建新数据;递归使用不当可能导致栈溢出。
函数式编程提供了一种不同的解决问题的思路,强调函数的纯粹性和数据的不变性。虽然在某些场景下可能不是最优选择,但它的核心概念和实践方式能够帮助我们编写更清晰、更健壮的代码。在实际开发中,可以根据具体需求灵活选择编程范式,甚至将函数式编程与其它范式结合使用。
理解函数式编程的核心概念,掌握纯函数、高阶函数和函数组合等技术,能够显著提升代码质量和开发效率。无论你是前端还是后端开发者,这些知识都将对你的编程实践产生积极影响。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
我理解的 JavaScript 函数式编程,都认为属于函数式编程的范畴,只要他们是以函数作为主要载体的。
给你的代码增加一点点函数式编程的特性,最近我对函数式编程非常感兴趣。这个概念让我着迷:应用数学来增强抽象性和强制纯粹性,以避免副作用,并实现代码的良好可复用性。同时,函数式编程非常复杂。
Async/await以及它底层promises的应用正在猛烈地冲击着JS的世界。在大多数客户端和JS服务端平台的支持下,回调编程已经成为过去的事情。当然,基于回调的编程很丑陋的。
如果你曾经了解或编写过JavaScript,你可能已经注意到定义函数的方法有两种。即便是对编程语言有更多经验的人也很难理解这些差异。在这篇博客的第一部分,我们将深入探讨函数声明和函数表达式之间的差异。
随着软件应用的复杂度不断上升,为了确保应用稳定且易拓展,代码质量就变的越来越重要。不幸的是,包括我在内的几乎每个开发者在职业生涯中都会面对质量很差的代码。这些代码通常有以下特征:
在js开发中,程序代码是从上而下一条线执行的,但有时候我们需要等待一个操作结束后,再进行下一步操作,这个时候就需要用到回调函数。 在js中,函数也是对象,确切地说:函数是用Function()构造函数创建的Function对象。
这篇文章主要介绍ES5中函数的4种调用,在ES5中函数内容的this指向和调用方法有关。以及ES6中函数的调用,使用箭头函数,其中箭头函数的this是和定义时有关和调用无关。
函数的三种定义方法分别是:函数定义语句、函数直接量表达式和Function()构造函数的方法,下面依次介绍这几种方法具体怎么实现,在实际编程中,Function()构造函数很少用到,前两中定义方法使用比较普遍。
微软 称excel就实现面向开发者的功能,也就是说我们不仅可以全新定义的公式,还可以重新定义excel的内置函数,现在Excel自定义函数增加了使用 JavaScript 编写的支持,下面就简单介绍下如何使用js来编写excel自定义函数。
这篇文章主要讲解:js立即执行函数是什么?js使用立即执行函数有什么作用呢?js立即执行函数的写法有哪些?
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!