有3个常见作用:1. 参数复用;2. 提前返回;3. 延迟计算/运行
1 参数复用
let fun = (function (...arg) {
let args1 = arg
return function (...a) {
let args2 = args1.concat(a)
console.log(args2)
}
})('提前设定参数')
fun('后添加参数')
2 提前返回逻辑,不用在程序执行时通过 if else 在返回相应逻辑。如果3次执行,那么只需要判断一次,否则判断3次
let p = 0
let fun = (function () {
if (p === 0) {
return function () {
// 100行逻辑
}
} else {
return function () {
// 100行逻辑
}
}
})()
fun(1)
fun(1)
fun(1)
3 延迟计算/运行
const fun = (function (...arge) {
return function () {
if (arguments.length === 0) {
console.log(arge.reduce((a,b) => a + b))
} else {
let arge2 = Array.from(arguments)
arge = arge.concat(arge2)
console.log(arge)
}
}
})()
fun(1)
fun(2)
fun(3)
fun()
4 add(1,2,3)(1)(2)(3)(4,5,6)(7,8)()
function add (...arge) {
console.log(arge)
return function _add (...arge2) {
if (arge2.length === 0) {
console.log(arge.reduce((a, b) => a + b))
} else {
arge = arge.concat(arge2)
return _add
}
}
}
add(1,2,3)(1)(2)(3)(4,5,6)(7,8)() // 42
5 通用的函数来对普通函数进行柯里化
可以看出来,柯里化其实是有特点的,需要一个闭包保存参数,一个函数来进行递归,这种模式是可以通过一个包装函数,对一些基本的函数进行包装之后的函数具有curry的特性。实现如下: // 通用的函数柯里化构造方法
function curry(func){
//新建args保存参数,注意,第一个参数应该是要柯里化的函数,所以args里面去掉第一个
var args = [].slice.call(arguments,1);
//新建_func函数作为返回值
var _func = function(){
//参数长度为0,执行func函数,完成该函数的功能
if(arguments.length === 0){
return func.apply(this,args);
}else {
//否则,存储参数到闭包中,返回本函数
[].push.apply(args,arguments);
return _func;
}
}
return _func;
}
function add(){
return [].reduce.call(arguments,function(a,b){return a+b});
}
console.log(curry(add,1,2,3)(1)(2)(3,4,5,5)(5,6,6,7,8,8)(1)(1)(1)());//69
6 优化
let fun = function (a) {
大量计算
return function (b) {
大量计算
}
}
let fun2 = fun(a)(b)
fun2(3)
fun2(4)
7 提前返回
let addEvent = function (el, type, fn, capture) {
if (window.addEventListener) {
el.addEventListener(type, fn)
} else if (window.attachEvent) {
el.attachEvent("on", type, fn)
}
}
addEvent(div, "click", fn, false)
优化
let addEvent2 = function () {
if (window.addEventListener) {
return function ( el, type, fn, capture ) {
el.addEventListener(type, fn)
}
} else if (window.attachEvent) {
return function ( el, type, fn, capture ) {
el.attachEvent("on", type, fn)
}
}
}
let fun = addEvent2()
fun(div, "click", fn, false)
8 延迟执行 不定参数
let fun1 = function () {
let all = []
return function m () {
if (arguments.length) {
all = all.concat(Array.from(arguments))
return m
} else {
console.log(all.reduce((a,b) => a + b))
}
}
}
let f = fun1()
f(1)(2)(3)
f(1)(2)(3)()
9 参数复用
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
function isNumber(obj) {
return Object.prototype.toString.call(obj) === '[object Number]';
}
function isString(obj) {
return Object.prototype.toString.call(obj) === '[object String]';
}
// Test
isArray([1, 2, 3]); // true
isNumber(123); // true
isString('123'); // true
const toStr = Function.prototype.call.bind(Object.prototype.toString);
// 改造前
[1, 2, 3].toString(); // "1,2,3"
'123'.toString(); // "123"
123.toString(); // SyntaxError: Invalid or unexpected token
Object(123).toString(); // "123"
// 改造后
toStr([1, 2, 3]); // "[object Array]"
toStr('123'); // "[object String]"
toStr(123); // "[object Number]"
toStr(Object(123)); // "[object Number]"
10 实现 currying 函数 (通用)
function currying(fn, length) {
length = length || fn.length; // 注释 1
return function (...args) { // 注释 2
return args.length >= length // 注释 3
? fn.apply(this, args) // 注释 4
: currying(fn.bind(this, ...args), length - args.length) // 注释 5
}
}
// Test
const fn = currying(function(a, b, c) {
console.log([a, b, c]);
});
fn("a", "b", "c") // ["a", "b", "c"]
fn("a", "b")("c") // ["a", "b", "c"]
fn("a")("b")("c") // ["a", "b", "c"]
fn("a")("b", "c") // ["a", "b", "c"]
注释 1:第一次调用获取函数 fn 参数的长度,后续调用获取 fn 剩余参数的长度
注释 2:currying 包裹之后返回一个新函数,接收参数为 ...args
注释 3:新函数接收的参数长度是否大于等于 fn 剩余参数需要接收的长度
注释 4:满足要求,执行 fn 函数,传入新函数的参数
注释 5:不满足要求,递归 currying 函数,新的 fn 为 bind 返回的新函数(bind 绑定了 ...args 参数,未执行),新的 length 为 fn 剩余参数的长度