目录
一、函数式编程的风格
- 变量类型可以是函数
- 值(literal)可以是函数
- 对象的字段可以是函数
- 函数的参数可以是函数
- 函数的返回值可以是函数
- 参数和返回值都是函数
- 高阶函数
二、无副作用
三、引用透明度
四、惰性计算(lazy evaluation)
一、函数式编程的风格
1. 变量类型可以是函数
我们在前面的基础部分学习到了很多的数据类型,在函数式编程中,变量类型也可以是函数。
这是一个普通的变量类型:
let Number: number = 100 | |
//使用 | |
console.log(100) |
我们类比一下,这是函数类型:
let comparnNumber = function comparnNumber(a: number, b: number){ //箭头函数(a: number, b: number) => a -b | |
return a - b | |
} | |
//使用,假设a是一个数组 | |
a.sort(conparnNumber) |
此时comparnNumber
就是一个函数类型
2. 值(literal)可以是函数
//值(literal)可以是函数 | |
//我们在使用函数时,可以直接使用数据类型,那么函数也可以 | |
//console.log(5)可也等效于下面: | |
let exp = 5 | |
console.log(exp) | |
//let comparnNumber1 = (a: number, b: number) => a - b | |
//let arr1 = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100] | |
//arr1.sort(comparnNumber1)可等效于下面: | |
let arr1 = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100] | |
arr1.sort((a: number, b: number)=> a- b) |
3. 对象的字段可以是函数
对象的字段也可以是函数,其实这里说的就是对象的方法,方法属于对象的字段,而方法本身就是函数
console.log(arr) | |
//对象emp1 | |
const emp1 = { | |
name: 'join', | |
salary: 8000, | |
//对象的字段可以是函数 | |
increaseSalary: function(p: number){ | |
this.salary *= p | |
} | |
} | |
emp1.increaseSalary(1.1) | |
console.log(emp1) | |
//输出结果: | |
{ | |
"name": "join", | |
"salary": 8800 | |
} |
4. 函数的参数可以是函数
函数的参数也可以是函数,下面来看看:
let arr = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100] | |
function comparnNumber(a: number, b: number){ | |
return b - a | |
} | |
console.log(arr.sort(comparnNumber)) //这里comparnNumber直接返回数据就不需要() |
5. 函数的返回值可以是函数
//函数的返回值可以是函数 | |
function CreatComparn(p: {smallerfirst: boolean} ){ //当有boolean类型时,我们最好使用对象字段作为参数 | |
if(p.smallerfirst){ | |
return (a: number, b: number) => a - b | |
}else{ | |
return (a: number, b: number) => b - a | |
} | |
} | |
let arr = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100] | |
arr.sort(CreatComparn({smallerfirst: true})) | |
console.log(arr) | |
//输出结果: | |
[1, 3, 3, 5, 5, 6, 66, 88, 98, 100] | |
[100, 98, 88, 66, 6, 5, 5, 3, 3, 1] |
6. 参数和返回值都是函数
//参数和返回值都是函数 | |
function logginComparer(comp: (a: number, b: number) => number) { | |
return (a: number, b: number) => { | |
//console.log('comparing', a, b) | |
return comp(a, b) | |
} | |
} | |
function comparer(a: number, b: number){ | |
return a- b | |
} | |
function CreatComparer(p: {smallerfirst: boolean} ){ | |
if(p.smallerfirst){ | |
return (a: number, b: number) => a - b | |
}else{ | |
return (a: number, b: number) => b - a | |
} | |
} | |
let arr = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100] | |
let cmp = CreatComparer({smallerfirst: true}) | |
arr.sort(logginComparer(cmp)) | |
console.log(arr) | |
//输出结果: | |
[1, 3, 3, 5, 5, 6, 66, 88, 98, 100] |
7. 高价函数
高阶函数:一个函数是两个或者两个以上的函数叠加起来的一个新函数,如:
- 函数的参数可以是函数
- 函数的返回值可以是函数
- 参数和返回值都是函数
- 里面的类型都属于高阶函数
二、 无副作用
当我们需要统计函数比较的次数时,最先想到的办法是定义一个全局变量compCount用来统计,当进行多次调用时,我们再把compCount的值设为零,下面是代码:
let compCount = 0 | |
function loggingComparer( comp: (a: number, b:number) => number ){ | |
return (a: number, b:number) => { | |
//引用全局变量compCount | |
compCount++ | |
return comp(a, b) | |
} | |
} | |
function createComparer(p: {smallerFirst: boolean}){ | |
if( p.smallerFirst){ | |
return (a: number, b:number) => a - b | |
}else{ | |
return (a: number, b:number) => b - a | |
} | |
} | |
let a = [5,2,1,6,7,10,5,25,16,23,11] | |
const comp = createComparer({smallerFirst: true}) | |
a.sort( loggingComparer(comp)) | |
//若需要再次执行的时候,就需要将全局变量置空 | |
compCount = 0 | |
a.sort(loggingComparer(comp)) | |
console.log(a) | |
console.log('compare count', compCount) |
但是这种方法,很容易在我们忘记将compCount重置,所以我们这里需要使用”闭包“(使用闭包解决全局变量往重置的问题)来实现比较次数的统计:
function logginComparer(logger: ( | |
a: number, b: number) => void, | |
comp: (a: number, b: number) => number) { | |
return (a: number, b: number) => { | |
logger(a, b) | |
return comp(a, b) | |
} | |
} | |
function comparer(a: number, b: number){ | |
return a - b | |
} | |
function CreatComparer( p: {smallerfirst: boolean} ){ | |
if(p.smallerfirst){ | |
return (a: number, b: number) => a - b | |
}else{ | |
return (a: number, b: number) => b - a | |
} | |
} | |
function processArray(a: number[]){ | |
let compCount = 0 | |
const logger = (a: number, b: number) => { | |
console.log('comparing', a, b) //打印日志 | |
compCount++ //记录 | |
} | |
const cmp = CreatComparer({smallerfirst:true}) | |
arr.sort(logginComparer(logger, cmp)) | |
return compCount | |
} | |
let arr = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100] | |
let CompCount1 = processArray(arr) | |
let CompCount2 = processArray(arr) | |
console.log(arr) | |
console.log('count comparing', CompCount1, CompCount2) | |
//输出结果: | |
/* | |
[log]: "comparing", 3, 1 | |
[LOG]: "comparing", 5, 3 | |
[LOG]: "comparing", 3, 5 | |
[LOG]: "comparing", 3, 3 | |
[LOG]: "comparing", 3, 5 | |
[LOG]: "comparing", 6, 3 | |
[LOG]: "comparing", 6, 5 | |
[LOG]: "comparing", 5, 3 | |
[LOG]: "comparing", 5, 6 | |
[LOG]: "comparing", 5, 5 | |
[LOG]: "comparing", 88, 5 | |
[LOG]: "comparing", 88, 6 | |
[LOG]: "comparing", 66, 5 | |
[LOG]: "comparing", 66, 6 | |
[LOG]: "comparing", 66, 88 | |
[LOG]: "comparing", 98, 5 | |
[LOG]: "comparing", 98, 66 | |
[LOG]: "comparing", 98, 88 | |
[LOG]: "comparing", 100, 5 | |
[LOG]: "comparing", 100, 88 | |
[LOG]: "comparing", 100, 98 | |
[LOG]: "comparing", 3, 1 | |
[LOG]: "comparing", 3, 3 | |
[LOG]: "comparing", 5, 3 | |
[LOG]: "comparing", 5, 5 | |
[LOG]: "comparing", 6, 5 | |
[LOG]: "comparing", 66, 6 | |
[LOG]: "comparing", 88, 66 | |
[LOG]: "comparing", 98, 88 | |
[LOG]: "comparing", 100, 98 | |
[LOG]: [1, 3, 3, 5, 5, 6, 66, 88, 98, 100] | |
[LOG]: "count comparing", 21, 9 | |
*/ |
这样一来对我们整个程序就没有了不必要的副作用,是程序更利于维护。
三、引用透明性
function add(a: number, b: number): number{ | |
return a + b | |
} | |
//下方代码从引用的角度来说他们是等价的 | |
//add(2, 3)返回值是5,和console.log(5)直接使用5没有区别 | |
console.log(5) | |
console.log(add(2, 3)) |
四、惰性计算(lazy evaluation)
function add(a: number, b: number):number{ | |
return a + b | |
} | |
//惰性计算指的是如下方的3+4只有在真正调用时才会算表达式的值,也就是7 | |
//javascript不支持惰性计算,所以在调用add函数时就会将3+4的值作为参数传进add函数的参数中 | |
add(2, 4+3) |