概念

函数式编程是一种编程范式,我们在其中尝试以纯数学函数风格绑定所有内容。它是一种声明式的编程风格。它的主要重点是“解决什么”,而命令式风格的主要重点是“如何解决”。它使用表达式而不是语句。计算表达式以产生值,而执行语句以分配变量。
函数式编程基于Lambda演算。而且,Lambda演算的函数可以接受函数作为输入参数和输出返回值。

特点

纯函数

这些函数有两个主要属性。首先,它们总是为相同的参数产生相同的输出,而不管其他任何事情。其次,它们没有副作用,即它们不修改任何参数或局部/全局变量或输入/输出流。后来的属性称为不变性。纯函数的唯一结果是它返回的值。它们是确定性的。

let arr = [1, 2, 3, 4, 5];

arr.slice(0, 3); // [1, 2, 3]
arr.slice(0, 3); // [1, 2, 3]

arr.splice(0, 3); // [1, 2, 3]
arr.splice(0, 3); // [4, 5]

// slice会改变参数,而splice会改变,所有slice是纯函数,而splice不是

递归

函数式语言中没有“for”或“while”循环。 函数式语言中的迭代是通过递归实现的。 递归函数反复调用自己,直到达到基本情况。

引用透明

引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。

函数是一等的并且可以是高阶的

一等(first class)函数被视为一等变量。 第一类变量可以作为参数传递给函数,可以从函数返回或存储在数据结构中。 高阶函数是将其他函数作为参数的函数,它们也可以返回函数。

变量是不可变的

在函数式编程中,我们不能在变量初始化后对其进行修改。 我们可以创建新变量——但我们不能修改现有变量,这确实有助于在整个程序运行时维护状态。 一旦我们创建了一个变量并设置了它的值,我们就可以完全确信该变量的值永远不会改变。

高阶函数

在数学和计算机科学中,高阶函数至少满足下列一个条件的函数:

  • 接受一个或多个函数作为输入
  • 输出一个函数

我们说闭包也是高阶函数,因为闭包输出了一个函数,满足高阶函数的第二个条件。

function square(x) {
    return x*x;
}
// add接受一个函数为输入,是高阶函数
function add(x, y, fn) {
    return fn(x) + fn(y);
}
add(10, -20, square); // 500

函数柯里化

坷里化(Currying)是把接受多个参数的函数变成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
function add(a, b, c) {
    return a + b + c;
}
let foo = function(a) {
    return function(b) {
        return function(c) {
            return a + b + c;
        }
    }
}
foo(1)(2)(3); // 6

// 抽象
function foo(fn, ...args1) {
    return function(...args2) {
        return function(...arg3) {
            return fn(..args1, ...args2, ...args3);
        }
    }
}
foo(add, 1)(2)(3);

// 自动坷里化
function foo(fn, ...args) {
    if (args.length >= fn.length) {
        return fn(...args);
    }
    return function(...args2) {
        return foo(fn, ...args, ...args2);
    }
}

偏函数

固定某个函数的一个或几个参数,返回一个新的函数,用来接收剩下的参数,这个返回的新函数就是偏函数。
function add(a, b, c) {
    return a + b + c;
}
function newAdd = add.bind(null, 1);
newAdd(2, 3); // 6

面试相关

通过更优雅的方式实现纯函数的解耦
let compose = (f, g) => (x => f(g(x)));

let add1 = x => x + 1;
let mul5 = x => x * 5;

compose(mul5, add1)(2); // 15

// 面试题 - 数组长度未知的情况下,拿到最后一项
let first = arr => arr[0];
let reverse = arr => arr.reverse();

let last = compose(first, reverse);

last([1, 2, 3, 4, 5]); // 5

参考文档:


feipeng123s
16 声望3 粉丝