- 函数是一等公民
- 只用表达式,不用语句
- 没有副作用
- 不修改状态
- 引用透明:相同输入有相同输出
- 没有副作用,相同输入有相同输出,不依赖外部状态
var x = [1,2,3,4,5]
x.slice(0,4) //[1, 2, 3, 4]
x.slice(0,4) //[1, 2, 3, 4]
x.splice(0,4) //[1, 2, 3, 4]
x.splice(0,4) //[5]
- 优点:可缓存性等
- 执行无数次还具有相同的效果
如Math.abs(Math.abs(-3))
function list() {
return Array.prototype.slice.call(arguments);
}
a
function addArguments(arg1, arg2) {
return arg1 + arg2
}
var list1 = list(1, 2, 3); // [1, 2, 3]
var result1 = addArguments(1, 2); // 3
// 创建一个函数,它拥有预设参数列表。
var leadingThirtysevenList = list.bind(null, 37);
// 创建一个函数,它拥有预设的第一个参数
var addThirtySeven = addArguments.bind(null, 37);
var list2 = leadingThirtysevenList();
// [37]
var list3 = leadingThirtysevenList(1, 2, 3);
// [37, 1, 2, 3]
var result2 = addThirtySeven(5);
// 37 + 5 = 42
var result3 = addThirtySeven(5, 10);
// 37 + 5 = 42 ,第二个参数被忽略
带一个函数和该函数的部分参数
const partial = (fn, ...args) => (...args2) => fn(...args, ...args2);
const add = (a, b, c) => a + b + c;
const add2 = partial(add, 2, 3);
console.log(add2(4)); //9
const add3 = partial(add, 2);
console.log(add3(3, 4)); //9
- 把一个多参数函数转换为一个嵌套一元函数的过程
- 传递给函数的一部分参数来调用它,让它返回一个函数去处理剩下的参数
function add(x,y){
return x + y
}
add(1,2) //3
//柯里化后
function add(x){
return function(y){
return x + y
}
}
add(1)(2) //3
const curry = (fn, arr = []) => {
return (...args) => {
return ((arg) =>
arg.length === fn.length ? fn(...arg) : curry(fn, arg))([
...arr,
...args,
]);
};
};
let curryTest = curry((a,b,c,d)=>a+b+c+d)
console.log(curryTest(1,2,3)(4)) //10
console.log(curryTest(1)(2)(3)(4)) //10
console.log(curryTest(1,2)(3)(4)) //10
- 优点:预加载函数,通过传递较少的参数,得到一个已经记住了这些参数的新函数
- 扩大适用范围,创建一个适用范围更广的函数,使本来只有特定对象才适用的方法,扩展到更多的对象
Function.prototype.uncurring = function () {
var self = this;
console.log("self", self);
return function () {
var obj = Array.prototype.shift.call(arguments);
return self.apply(obj, arguments);
};
};
var push = Array.prototype.push.uncurring();
var obj = {};
push(obj, "a", "b");
console.log(obj);
结果:
- 拆平洋葱代码f(g(x))
const compose = (f, g) => (x) => f(g(x));
let first = (arr) => arr[0];
let reverse = (arr) => arr.reverse();
let last = compose(first, reverse);
console.log(last([1, 2, 3, 4, 5])); //5
- compose函数只能接受一个参数的函数,接受多个参数不能被直接组合的函数 可以借助偏函数包裹后继续组合
const toUpperCase = word => word.toUpperCase()
const split = x=>word=>word.split(x)
var f= compose(split(' '), toUpperCase)
console.log(f('123 45')) //["123", "45"]
以函数作为参数,返回一个新函数
- 函数内部最后一个动作是函数调用
- 递归需要保存大量的调用记录,很容易发生栈溢出
- 函数运行最后一步调用自身
- 函数最后一行调用其它函数并返回是尾调用
- 尾递归调用栈永远都是更新当前的栈帧,避免爆栈,即帧复用,只创建一个sum函数,每次调用只传入参数
- 但是堆栈信息丢失了,开发者难以调试