JavaScript 中的函数式编程
函数是函数式编程中最重要的部分(尤其是在 JavaScript 中)。职能 是帮助开发人员执行函数式编程的单一来源。通常缩写为 FP,它围绕函数展开,正是我们使用函数的方式使我们的代码具有功能性。没有函数,就没有 FP。那么问题来了,函数到底是什么?
简单来说,函数就是可以多次执行的代码集合。我们大多数人将函数与过程混淆了。但它们是独立的实体。
PROCEDURE | FUNCTION |
A procedure may or may not be take input. | A function always take input(in FP). |
A procedure may or may not return output. | A function always returns the output. |
在函数式编程中,我们应该尽可能地使用函数。
输入:在一般编程中,我们可以互换使用带参数的实参,但它们不是同一个。参数是我们通过函数调用传入的数据,参数是我们在函数定义中接收的数据。
在 JavaScript 中,参数的数量不必总是与形参相同。如果我们传递较少的参数,那么剩余的参数将在函数中作为值未定义,如果我们传递的参数多于声明的参数,则剩余的参数保持不变。
我们可以在不定义单个参数的情况下获取所有参数,将参数用作类似数组的参数 object ,但这不是一个好习惯。
Do you know every function has an internal property named arguments. Have you ever notice why it is called arguments not parameters?
注意: Argument 是一个类似数组的对象,我们可以在函数内部访问它。它包含传递给函数的属性。因为我们谈论的是传递给函数的属性,而不是接收属性作为参数的属性。
- 参数是一个类似数组的对象。我们可以使用数组索引访问值,但不能使用forEach、map、reduce等数组方法,因为它类似于数组但不是数组。
- 一个论点 对象包含传递给该函数的参数值(因此称为参数)。在下面的程序中,我们可以看到参数的输出。它打印我们作为参数传递的所有值。
Javascript
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);
Javascript
// 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 )
Javascript
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
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") );
Javascript
const arr = [1, 2, 3, 4, 5, 6];
arr.forEach(function printArrayValues(val) {
console.log(val);
});
Javascript
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);
Javascript
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));
输出:
注意:从 ES5 开始,使用参数不是一个好的做法。你应该避免使用它。但是,如果您使用参数,则对象仅限于长度属性。
在函数式编程中,我们严格注意函数声明中的参数数量,称为arity 。我们必须注意arity,因为有时我们必须在函数内部传递一个函数,然后我们必须考虑兼容性。
Javascript
// 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
元数为 1 的函数称为一元函数,类似地,元数为 2 的函数称为二元函数,大于 2 的元数称为n 元函数。
长度函数可能有问题。比方说,如果有默认参数或剩余参数,那么该参数不包括在长度中。
Javascript
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 引擎)或内部(由开发人员)返回输出。
Javascript
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") );
输出:
注意:建议在函数式编程中从函数返回值。如果您想返回多个值,则可以使用数组或对象。
你知道在 JavaScript 中, return关键字不仅使用函数返回值,还可以用于流控制语句中。这意味着我们可以在函数执行的任何地方或任何地方停止函数的执行。可能存在一个函数中可能有多个返回语句的情况。但这只是让开发人员搞不清楚该函数是如何工作的。在一个函数中使用多个返回只是,不是一个好习惯。
函数可以返回值众所周知,函数可以返回值。它可以是原语、数组或对象。
注意:您在编写 JavaScript 时是否更喜欢分号 (;)。如果是,那很好,但如果不是,那么我的朋友你应该这样做。我知道这应该是开发人员的偏好,但在 JavaScript 中建议使用分号。 JavaScript 使用自动分号插入 (ASI)。如果您没有插入分号,那么 ASI 就会起作用,并且可能会产生影响。可能有一些严重的错误。
您一定期待identityObject返回一个对象,但它会返回undefined 。
JavaScript engine is smart enough and know where to insert semicolon. But why to depend on engine.
一个函数可以返回另一个函数
如果一个函数返回或接收一个或多个函数值,则该函数称为高阶函数。
Javascript
const arr = [1, 2, 3, 4, 5, 6];
arr.forEach(function printArrayValues(val) {
console.log(val);
});
输出:
在上面的程序中, arr是一个数组,我们使用forEach方法打印所有值。 forEach()是一个高阶函数,需要一个函数作为参数。
我们在日常生活中使用高阶函数,FP 也不例外。 FP 在每个地方都使用高阶。现在是时候介绍闭包了。
闭包就是要记住作用域变量,即使作用域发生了变化。我们不能在没有闭包的情况下进行 FP,而闭包就是从另一个函数函数记住作用域。我们将在另一篇文章中讨论闭包。
ES6 箭头函数:我们都听说过箭头函数。因为它有更短的语法并且没有函数关键字。
Javascript
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);
输出:
大多数用户更喜欢箭头函数,但我不建议使用它。以下是原因
- 使用箭头函数进行调试并不容易,因为箭头函数是一个匿名函数,如果在任何情况下我们都会遇到一些错误,并且我们调试我们的应用程序,那么在函数堆栈中我们将不会获得函数名称。
- 我们总是需要注意下面描述的箭头函数的语法。
箭头函数规则:
- 我们可以去掉函数关键字。
- 如果箭头函数中有一条语句,我们可以删除return关键字。
- 如果我们想返回一个对象,我们必须使用return关键字。
Javascript
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));