JavaScript 函数式编程
函数是函数式编程中最重要的部分(尤其是在JavaScript中)。 函数 是帮助开发人员进行函数式编程的单一来源。通常简写为FP,它围绕着函数展开,我们使用函数的方式使我们的代码变得函数式。没有函数,就没有FP。所以问题是什么是函数?
简单来说,函数是一段可以执行多次的代码集合。我们大多数人会将函数与过程混淆,但它们是不同的实体。
| 过程 | 函数 |
|---|---|
| 过程可能接受输入,也可能不接受(在FP中)。 | 函数总是接受输入(在FP中)。 |
| 过程可能返回输出,也可能不返回。 | 函数总是返回输出。 |

在功能编程中,我们应该尽可能多地使用函数。
输入: 在一般的编程中,我们可以互换使用参数和参数,但它们不是相同的。参数是我们通过函数调用传递的数据,而参数是我们在函数定义中接收到的数据。

在JavaScript中,参数的数量不一定与实参的数量相同。如果我们传递了较少的实参,函数中剩下的参数将以undefined的值存在;如果我们传递了较多的实参,多余的实参则不会被使用。
我们可以在不定义任何参数的情况下获取所有实参,使用的方法是将arguments作为类数组对象,但这不是一个好的实践。
你知道每个函数都有一个内部属性叫做 arguments 吗?你注意到为什么它被称为 arguments 而不是 parameters 吗?
注意: 实参是我们可以在函数内部访问的类数组对象。它包含作为实参传递给函数的属性。由于我们讨论的是传递给函数的属性,而不是作为参数接收属性的函数。
- 实参是一个类数组对象。我们可以使用数组索引来访问值,但不能像数组一样使用数组方法,例如forEach、map、reduce等。
- 实参对象包含传给函数的实参的值(所以称为arguments)。在下面的程序中,我们可以看到arguments的输出。它打印我们作为实参传递的所有值。
function print(a, b) {
console.log(a);
console.log(b);
console.log(arguments);
console.log(arguments[0]);
console.log(arguments[1]);
}
print(1, 2, 3, 4);
输出:

注意: 从ES5开始,使用arguments被认为不是一种好的做法。你应该避免使用它。但如果你使用arguments,这个对象只限制在 length 属性。
在函数式编程中,我们严格控制函数声明中的参数数量,这被称为 空元 。我们必须关注空元,因为有时我们需要在函数内部传递一个函数,然后我们就要考虑兼容性。
// The arity of maipulateJSON is 2. we can find
// arity with length property of a function
function manipulateJSON(json, options) {
console.log(json, options)
}
console.log( manipulateJSON.length )
输出:
2
功能的arity为1被称为 一元 函数,类似地,arity为2的函数被称为 二元 函数,而arity大于2的函数被称为 n元 函数。
length函数可能存在问题。比如说,如果存在默认参数或剩余参数,则该参数不包括在长度中。
function printDefault(fn, args = {}) {
fn(args);
}
function printRest(fn, ...args) {
fn(...args);
}
printDefault(console.log, { name: "Praveen" });
printRest(console.log, 1, 2, 3, 4);
console.log(printDefault.length);
console.log(printRest.length);
输出:

注意: 在JavaScript中,函数总是返回输出,无论是外部(由JS引擎)还是内部(由开发者)。
function print1( name ) {
console.log( name );
}
function print2( name ) {
console.log( name );
return;
}
function print3( name ) {
console.log( name );
return undefined;
}
console.log( print1("Praveen") );
console.log( print2("Praveen") );
console.log( print3("Praveen") );
将下面的英文翻译成中文,不解释,保留HTML格式:
输出:

注意: 功能型编程中建议从函数中返回一个值。如果你想返回多个值,可以使用数组或对象。
你知道JavaScript中, return 关键字不仅用于函数返回值,还可以用于流程控制语句中。这意味着我们可以在函数的任何地方停止函数的执行。可能会出现函数中有多个返回语句的情况。但是这会让开发者很困惑,难以理解函数的工作方式。在函数中使用多个返回语句并不是一个好的做法。
函数可以返回值 我们都知道函数可以返回值。可以是基本类型、数组或对象。
注意: 在编写JavaScript代码时,你更喜欢使用分号(;)吗?如果是 是 那太好了,但如果 不是 那么朋友,你应该使用分号。我知道这应该是开发者的个人偏好,但在JavaScript中推荐使用分号。JavaScript使用 自动分号插入(ASI) 。如果你没有插入分号,则会触发ASI,可能会带来一些严重的错误。

你一定期望 identityObject 返回一个对象,但实际上它会返回 undefined 。
JavaScript 引擎足够聪明,能够确定在何处插入分号。但为什么要依赖于引擎。
函数可以返回另一个函数
如果一个函数返回或接收一个或多个函数值,那么该函数被称为 高阶函数 。
const arr = [1, 2, 3, 4, 5, 6];
arr.forEach(function printArrayValues(val) {
console.log(val);
});
输出:

const numbers = [1, 2, 3, 4, 5, 6];
const newNumbers = numbers.map(function (x) {
return x * 2;
});
console.log(newNumbers);
const arrowNewNumbers = numbers.map((x) => x * 2);
console.log(arrowNewNumbers);
输出:

大多数用户更喜欢箭头函数,但我不建议使用它。以下是原因:
- 使用箭头函数进行调试不容易,因为箭头函数是匿名函数,如果在任何情况下我们遇到了一些错误,并且要调试我们的应用程序,那么在函数堆栈中我们将无法获取函数名称。
- 我们必须始终注意下面描述的箭头函数的语法。
箭头函数的规则:
- 我们可以省略
function关键字。 - 如果箭头函数中只有一个语句,我们可以省略
return关键字。 - 如果想要返回一个对象,则必须使用
return关键字。
const numbers = [1, 2, 3, 4, 5, 6];
// We can drop function and return keyword
const version1 = numbers.map((x) => x * 2);
// If there is single parameter thern we
// can also drop parenthesis
const version2 = numbers.map(x => x * 2);
// If we have to return an object then we
// have to use curly braces with return
// keyword because compiler gets easily
// confused with a block.
// const version3 = (arr) => { array: arr } // ERROR
const version3 = function (arr) {
return {
array: arr,
};
};
console.log(version1);
console.log(version2);
console.log(version3(numbers));
极客教程