数学中的函数是什么?
y = f(x)
从上面的例子可以看出:
- 函数必须总是接收一个参数
- 函数必须总返回一个值
- 函数应该依据接收到的参数(例如X)而不是外部环境运行
- 对于一个给定的X,只会输出唯一的一个Y
接下来让我们来看一个计税函数的例子:
let percentValue = 5;
const calculateTax = (value)=> value/100 * (100 + percentValue);
从数学函数的定义上面的calculateTax
函数不能称为一个真正意义上的函数;但我们对它稍加改动,便能让它成为一真正意义上的函数
const calculateTax = (value,percentValue)=> value/100 * (100 + percentValue);
函数式编程主要是基于数学函数和它的思想,它是一种范式(范式是什么请大家自行理解),我们能够以此创建仅依赖于输入就可以完成自身逻辑的函数
引用透明性
根据数据函数的定义:我们可以得出一个结论:所有的函数对于相同的输入,都将返回相同的值,函数的这一属性被称为引用透明性
举个例子:
const identity = i => i
假设该函数被其他的函数调用:
sum(4,5) + identity(1)
根据引用透明性的定义, 我们可以把上面的语句转换为:
sum(4,5) + 1
该过程被称为 替换模型,因为你可以直接替换函数的结果(主要因为函数的逻辑不依赖于其他的全局变量),这与他的值是一样的。这使并发代码和缓存成为了可能
命令式,声明式,抽象
函数式编程主张声明式编程和编写抽象的代码
让我们看一个例子,用命令式方法遍历一个数组:
const array = [1,2,3];
for(let i = 0; i < array.length; i++)
console.log(array[i]); //打印1,2,3
从这段代码可以看出:我们在告诉程序,我们要 如何
做,首先我们告诉编辑器我们要获取数组长度,然后循环数组,用索引获取每一个数组元素,然后打印还数组元素等等,我们将之称为命令式
解决方案, 命令式编程
主张告诉编译器 如何做
让我再接着看另一个例子
const array = [1,2,3];
array.foreach(element => console.log(element)); //打印1,2,3
从上面的代码可以看出,这段代码没有在告诉编译器如何做,而是在让开发者只需要关心做什么
, 这个非常重要。
函数式编程主张以抽象的方法创建函数,这些函数能够在代码的其他部分被重用
纯函数
纯函数是对给定的输入返回相同的输出的函数, 纯函数遵守引用透明性
const double = value => value * 2;
函数式编程的好处
- 易于测试
- 并发执行
- 可缓存
函数式编程在Javascript中的应用
问题: Javascript是函数式编程语言吗?
答案是不是,让我们来看一个例子:
const uselessFunc = () => {}
因为函数式编程语言主张函数必须接受一个或多个参数并且返回一个值,但Javascript非常适合函数式编程范式,因为Javascript语言支持将函数作为参数,传递给另一个函数(当一门语言允许函数作为任何其他任何数据类型使用时,函数被称为一等公民)
高阶函数(Higher-Order Function)
接受另一个函数作为其参数的函数称为高阶函数
让我们来看一个简单的例子:
const every. = (arr, fn) => {
let result = true;
for(let i = 0; i< arr.length; i++)
result = result && fn(arr[i])
return result;
}
every([NaN,NaN,NaN], isNaN)
=> true
every([NaN,NaN, 4], isNaN);
=> false
让我们再来看一个例子:
const foreach = (arr, fn) => {
for(let i = 0; i < arr.length; i++){
fn(arr[i]);
}
}
foreach([1,2,3], (i)=> console.log(i));
//打印1,2,3
从上面的两个例子可以看出: 高阶函数本身其实是一种抽象,抽象让我们专注于我们需要做什么,而无须关心底层的概念和实现
闭包和高阶函数(Higher-Order Function)
什么是闭包
function outer(){
function inner(){
}
}
从技术上讲,闭包有3个可访问的作用域:
(1)在自身声明之内声明的变量
(2)对全局变量的访问
(3)对外部函数变量的访问
function outer(){
function inner(){
let a = 5;
console.log(a)
}
inner(); // 调用inner函数
}
//打印出5;
let global = "global";
function outer(){
function inner(){
let a = 5;
console.log(global)
}
inner(); // 调用inner函数
}
//打印出global;
let global = "global";
function outer(){
let outer = "outer";
function inner(){
let a = 5;
console.log(outer)
}
inner(); // 调用inner函数
}
//打印出outer;
闭包在高阶函数中的应用
让我们再来看一些例子:
const tap = value => (fn) => (typeof(fn) === "function" && console.log(value));
tap("fun")((it) => console.log("value is", it));
=> value is fun
=> fun
函数式编程在数组中的应用
- map 函数
const map= (array, fn) => {
let result = [];
for(const value of array)
result.push(fn(value));
}
return result;
map([1,2,3], x => x * x); => [1,4,9];
- filter函数
const filter = (array, fn) => {
let result = [];
for(const value of array){
fn(value) ? result.push(value): undefind
}
}
filter([1,2,3,4,5], (i) => i % 2 === 0); => [2,4]
柯里化(Higher-Order Function)
例子:
const add = (x,y) => x + y;
const addCurried = x = > y => x + y;
addCurried(4);
addCurried(4)(4)
=> 8
柯里化是一个把多参数函数转化为一个嵌套的一元函数的过程
为什么要进行柯里化,柯里化的好处,函子, 组合管道请见下次分享
网友评论