基本概念
满足下列条件之一的函数就可以称为高阶函数。
1、函数作为参数被传递;
2、函数作为返回值输出。
函数作为参数被传递
把函数当作参数传递,这代表我们可以抽离出一部分容易变化的业务逻辑,把这部分业务逻辑放在函数参数中,这样一来可以分离业务代码中变化与不变的部分。其中一个重要应用场景就是常见的回调函数。
例子:
[1, 4, 2, 5, 0].sort((a, b) => a - b);
//输出:[0, 1, 2, 4, 5]
[0, 1, 2, 3, 4].map(v => v + 1);
//输出:[1, 2, 3, 4, 5]
[0, 1, 2, 3, 4].every(v => v < 5);
//输出:true
函数作为返回值输出
让函数继续返回一个可执行的函数,意味着运算过程是可延续的。
例子:
const fn = (() => {
let myFamily = [];
return {
addPerson(name) {
if (myFamily.includes(name)) {
return false;
}
myFamily.push(name);
},
showPerson(name) {
if (Object.is(myFamily.length, 0)) {
return false;
}
return myFamily.join(",");
}
}
})();
fn.addPerson("爸爸");
fn.addPerson("妈妈");
fn.showPerson(); //输出:爸爸,妈妈
同时满足两个条件的高阶函数
例子:
const plus = (...args) => {
let n = 0;
for (let i = 0; i < args.length; i++) {
n += args[i];
}
return n;
}
const mult = (...args) => {
let n = 1;
for (let i = 0; i < args.length; i++) {
n *= args[i];
}
return n;
}
const createFn = (fn) => {
let obj = {};
return (...args) => {
let keyName = args.join("");
if (keyName in obj) {
return obj[keyName];
}
obj[keyName] = fn.apply(null, args);
return obj[keyName];
}
}
let demo1 = createFn(plus);
console.log(demo1(2, 2, 2)); //输出:6
let demo2 = createFn(mult);
console.log(demo2(2, 2, 2)); //输出:8
函数柯里化
函数柯里化又称部分求值。一个柯里化的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
例子:
const cost = (() => {
let arr = [];
return (...args) => {
if (args.length === 0) {
let money = arr.reduce((p, c) => p + c);
return money;
} else {
arr.push(parseInt(args));
}
}
})();
cost(100);
cost(100);
cost();
//输出:200
上例中,当调用cost()时,如果明确地带上了一些参数,表示此时并不进行真正的求值计算,而是把这些参数保存起来,此时让cost函数返回另外一个函数。只有当我们以不带参数的形式执行cost()时,才利用前面保存的所有参数,真正开始进行求值计算。函数柯里化赋予函数的是一种“预加载”的能力。
高价函数的意义
闭包和高阶函数在JavaScript的设计模式中应用极多,后续有关于设计模式的手记中会详细讲解。
如有错误,欢迎指正,本人不胜感激。