高阶函数
接收函数作为参数或将函数作为输出返回的函数(高阶函数是对其他函数进行操作的函数)
柯里化和反柯里化是高阶函数的一种应用,通俗的说,函数可以作为参数传递到函数中,这个作为参数的函数叫回调函数,而拥有这个参数的函数就是高阶函数,在高阶函数执行时,由于回调函数的内部逻辑不同,高阶函数的执行结果也不同,非常灵活,也被叫做函数式编程
// 比如:数组中的map方法,接收一个函数作为参数
let arr = [1, 2, 3];
let res = arr.map((item, index) => {
return item + 1;
});
console.log(res); // [ 2, 3, 4 ]
函数柯里化
把一个n参数的函数,转化为n个单参数函数,即每一个函数只有一个参数(阮一峰对于柯里化和函数的合成的理解)
// 普通函数
function getAddress(country, province, city){
console.log(country + '-' + province + '-' + city);
}
getAddress('中国','湖北','武汉') // 中国-湖北-武汉
getAddress('中国','浙江','杭州') // 中国-浙江-杭州
// 柯里化函数
function getAddress(country) {
return function (province) {
return function (city) {
console.log(country + "-" + province + "-" + city);
};
};
}
let test = getAddress('中国')
test('湖北')('武汉') // 中国-湖北-武汉
test('浙江')('杭州') // 中国-浙江-杭州
反柯里化
柯里化的过程是将函数拆分成功能更具体化的函数,反柯里化在于扩大函数的适用性,使本来作为特定对象所拥有的功能函数可以被任意对象所使用(一篇关于函数式编程的文章)
//反柯里化通用式应用
function uncurring(fn) {
return function (...args) {
console.log(args); // [ { name: 'Panda', age: 16 }, 'name', 'age' ]
return fn.call(...args);
};
}
// 构造函数 F
function F() {}
// 拼接属性值的方法
F.prototype.concatProps = function () {
let args = Array.from(arguments);
console.log(args); // [ 'name', 'age' ]
return args.reduce((prev, next) => `${this[prev]}&${this[next]}`);
};
// 使用 concatProps 的对象
const obj = {
name: "Panda",
age: 16,
};/* */
// 使用反柯里化进行转化
const concatProps = uncurring(F.prototype.concatProps);
let res = concatProps(obj, "name", "age"); // Panda&16
console.log(res); // Panda&16
图解:
偏应用函数
一个函数有多个参数,预先填充原始函数的部分参数,返回的函数接收剩余的参数
function getAddress(country) {
return function (province,city) { // 余下的所以参数
console.log(country + "-" + province + "-" + city);
};
}
let test2 = getAddress("中国")
test2('湖北','武汉') // 中国-湖北-武汉
test2('浙江','杭州') // 中国-浙江-杭州
闭包
一个函数里面创建另一个函数,指有权访问另一个函数作用域中的变量的函数(MDN中闭包的解释)
文章有过记录,请移步
递归函数
一个函数在内部调用自身的操作(MDN中递归的解释)
求和
// 递归求和 复杂度:O(n)
function f(x) {
if (x == 1) return 1;
return x + f(x-1);
}
console.log(f(5)); // 15
// 尾递归求和 复杂度:O(1)
function f(n, total = 1) {
if (n == 1) return total;
return f(n - 1, n + total);
}
console.log(f(5)); // 15
求数组和
// 尾递归求数组和
function sum(arr, total) {
if (arr.length == 0) {
return total;
}
return sum(arr, total + arr.shift());
}
console.log(sum([10, 20, 30], 0)); // 60
// 递归求数组和
function sum(arr) {
function f(i) {
if (i < arr.length) {
return f(i + 1) + arr[i]; // 递归调用
} else {
console.log(i, "终止条件"); // 3 终止条件
return 0;
}
}
return f(0);
}
console.log(sum([10, 20, 30])); //60
数组扁平化
const flatten = (arr) => {
let newArr = [];
arr.forEach((item) => {
if (Array.isArray(item)) {
newArr = newArr.concat(flatten(item));
// 最小单元想象成这种数据结构:[3, [4, 5]]去走里面的if-else条件判断
} else {
newArr.push(item);
}
});
return newArr;
};
const arr = [1, [2, [3, [4, 5]]], 6];
console.log(flatten(arr)); // [ 1, 2, 3, 4, 5, 6 ]
如果不好理解,通过debugger可以发现如下规律:
// arr的变化
[1, [2, [3, [4, 5]]], 6]
[2, [3, [4, 5]]]
[3, [4, 5]]
[4, 5]
// newArr的变化
item push成 [4, 5]
item concat成 [3].concat([4, 5]) => [3, 4, 5]
item concat成 [2].concat([3, 4, 5]) => [2, 3, 4, 5]
item concat成 [1].concat([2, 3, 4, 5]) => [1, 2, 3, 4, 5]