函数式编程
为什么要学习函数式编程
- 方便测试、方便并行处理
- 函数式编程可以抛弃this
- 函数式编程收到越来越多的关注
- 有很多库可以帮助我们进行函数式开发:lodash 、underscore 、ramda
什么是函数式编程
函数式编程(Functional Programming FP) FP是编程规范式之一
- 面向对象编程思维方式 :把现实世界中的事物抽象成程序世界中的类和对象,通过封装继承多态来演示事物事件的联系
-
函数式编程思维方式: 把现实世界中的事物和事物之间的联系抽象到程序世界(对运算过程进行抽象)
- 函数式编程中的函数不是程序中的函数(方法),而是数学中的函数即映射关系
- 相同的输入始终要得到相同的输出
- 函数式编程用来描述数据(函数)之间的映射
//非函数式
var num1 = 1;
var num2 = 2;
var num3 = num1 + num2;
console.log(num3);
//函数式
function add (n1,n2){
return n1 + n2
}
var sum = add(2,3);
console.log(sum);
tips: 函数式编程好处就是可以重用代码
函数式一等公民
First-class Function
- 函数可以存储在变量中
- 函数作为参数
- 函数作为返回值
//把函数赋值给变量
var fn = function(){};
高阶函数-函数作为参数
什么是高阶函数
-
高阶函数
- 可以把函数作为参数传递给另一个函数
- 可以把函数作为另一个函数的返回结果
- 函数作为参数
//实现forEach函数
function forEach(array,fn){
for(var i=0;i < array.length;i++){
fn(array[i]);
}
}
//实现filter
function filter(array,fn){
let temp = [];
for(var i=0;i < array.length;i++){
if(fn(array[i])) temp.push(array(i));
}
return temp;
}
tips: 函数作为参数可以让函数更灵活,无需考虑函数内部实现
高阶函数-函数作为返回值
//基本语法:
function makeFn (){
let msg = "函数作为返回值基本语法"
return function(){
console.log(msg)
}
}
//模拟once函数 只让函数执行一次 例子:支付的时候只执行一次
function once(fn){
//控制fn只执行一次
let done = false;
return function(){
if(!done){
done = true;
return fn.apply(this,arguments);
}
}
}
//测试once
let pay = once(function(money){
console.log(`支付:${money}RMB`);
})
pay(5) //执行
pay(6) //不执行
pay(7) //不执行
pay(8) //不执行
高阶函数的意义
- 抽象可以帮助我们屏蔽细节,只需关注我们的目标
- 高阶函数是用来抽象通用的问题
常用的高阶函数
- forEach 方法用于调用数组的每个元素,并将元素传递给回调函数
- map 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
- filter 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素
- every 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)
- some 方法用于检测数组中的元素是否满足指定条件(函数提供)
- find/findIndex 方法返回通过测试(函数内判断)的数组的第一个元素的值
- reduce 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
- sort 方法用于对数组的元素进行排序
- ......
//实现map方法
const map= function (array,fn) {
let temp = [];
for(let i=0;i<array.length;i++){
temp.push(fn(array[i]));
}
return temp;
}
//测试
var arr1 = [1,2,3,4,5];
map(arr1,function(item){return item * item}); // [1, 4, 9, 16, 25]
//实现every方法
const every = function(array,fn){
let condition = true;
for(var value of array){
condition = fn(value);
if(!condition) break;
}
return condition;
}
//测试
var arr2 = [1,2,3,4,5,6];
every(a1,item=>item < 10);//true
every(a1,item=>item > 5);//false
//实现some方法
const some = function(array,fn){
let condition = false;
for(var value of array){
condition = fn(value);
if(condition) break;
}
return condition;
}
var arr3 = [1,3,5,7,9];
some(arr3, item=>item % 2===0); //false
var arr4 = [1,2,3,4,5];
some(arr4, item=>item % 2===0);//true
闭包
-
闭包(Closure): 函数和其周围状态(词法环境)的引用捆绑在一起形成闭包
- 可以在另一个作用域中调用另一个函数的内部函数并访问到该函数的作用域中的成员
- 闭包的本质: 函数在执行的时候会放到一个执行栈上当函数执行完毕之后会从执行栈上移除,
但是堆上的作用域成员因为被外部应用不能释放
,因此内部函数依然可以访问外部函数的成员
//闭包
function f1(){
let data = 1;
}
f1();//f1执行 data会被释放掉
function fn (){
let data = 1;
return function(num){
data+= num;
return (data);
}
}
var add = fn();//fn执行 data不会被释放
add(1);
//案例1. 经常求数字的平方
//例 Math.pow(4,2);
// Math.pow(6,2);
function mackPower(power){
return function(number){
return Math.pow(number,power);
}
}
//求平方
let power2 = mackPower(2);
//求三次方
let power3 = mackPower(3);
console.log(power2(5));
console.log(power2(6));
console.log(power3(7));
//案例2 求员工工资 员工工资 = 基本工资+绩效工资 同级别绩效工资相同 绩效工资浮动
//员工1 级别1 基本工资12000 绩效工资300
//员工2 级别2 基本工资15000 绩效工资200
//员工3 级别2 基本工资15000 绩效工资100
function makeSalary(base){
return function(performance){
return base + performance;
}
}
//等级1
let salaryLevel1 = makeSalary(12000);
//等级2
let salaryLevel2 = makeSalary(15000);
//员工1
salaryLevel1(300);//12300
//员工2
salaryLevel2(200);//15200
//员工3
salaryLevel2(100);//15100