///
/**
* @obj
* @desc 操作函数的相关方法。所有函数不会改变实参的值,会返回操作后的结果。
* @method curry - 将传入的函数柯里化
* @method compose - 将所有传入的函数从右向左组合起来
*/
const fn: FunctionModule = {
curry: function (fn: Function): CurryFunction {
let paramsLength: number = fn.length;
function closure(params: any[]): CurryFunction {
let wrapper: CurryFunction = function (...newParams: any[]) {
let allParams = [...params, ...newParams];
if (allParams.length < paramsLength) {
return closure(allParams);
} else {
return fn.apply(null, allParams);
}
};
return wrapper;
}
return closure([]);
},
compose: function (...fn: any[]): (...params: any[]) => Return {
return (...params: any[]): Return => {
let i = fn.length - 1;
let result = fn[i].apply(null, params);
while (--i >= 0) {
result = fn[i](result);
}
return result;
};
},
debounce: function (
fn: (...params: any[]) => Return,
wait: number,
immediate: boolean
): Executor {
const now: () => number = Date.now.bind(Date);
let lastTime: number = 0;
let timer: number = null;
let params: IArguments = null;
let _this: Function | null = null;
function later(): void {
const nowTime: number = now();
if (nowTime - lastTime < wait) {
const remainTime = wait - (nowTime - lastTime);
timer = setTimeout(later, remainTime);
} else {
debouncer.result = fn.apply(_this, params);
timer = null;
_this = null;
params = null;
}
}
function execute(): (Return | null) {
lastTime = now();
_this = this;
params = arguments;
try {
if (immediate && timer === null) {
debouncer.result = fn.apply(_this, params);
}
return debouncer.result;
} finally {
if (timer === null) {
timer = setTimeout(later, wait);
}
}
}
const debouncer: Executor = {
execute,
result: null,
};
return debouncer;
},
throttle: function (
fn: (...params: any[]) => Return,
wait: number,
{
isExecuteAtStart = true,
isExecuteAtEnd = true,
}: ThrottleOptions = {
isExecuteAtStart: true,
isExecuteAtEnd: true,
}
): Executor {
let timer: number = null;
let _this: Function = null;
let params: IArguments = null;
function execute(): (Return | null) {
_this = this;
params = arguments;
if (isExecuteAtStart && timer === null) {
executor.result = fn.apply(_this, params);
_this = null;
params = null;
}
if (isExecuteAtEnd) {
if (timer === null) {
timer = setTimeout(function () {
executor.result = fn.apply(_this, params);
_this = null;
params = null;
timer = null;
}, wait);
}
}
return executor.result;
}
const executor: Executor = {
execute,
result: null
};
return executor;
}
};
export default fn;
export const curry = fn.curry;
export const compose = fn.compose;
export const debounce = fn.debounce;
export const throttle = fn.throttle;