基本概念
函数柯里化(function currying):创建已经设置好一个或多个参数的函数。
函数的柯里化的基本方法和函数绑定是一样的:使用一个闭包 并 return一个函数。
两者的区别:当函数被调用时,返回的函数还需要设置一些传入的参数。
function add(num1, num2) {
return num1 + num2;
}
function curryAdd(num2) {
return add(5, num2);
}
console.log(add(2, 3)); // 5
console.log(curryAdd(3)); // 8
上面代码定义了两个函数,add()和curryAdd()。后者本质上是在任何情况下第一个参数为5的add()版本。尽管技术上来讲,curryAdd()并非柯里化的函数,却很好的展示了柯里化的概念。
手写代码
原生:
function curry(fn) {
//1.一个闭包
//截取内置对象arguments第二位以后的参数, 第一位参数是fn
var args = Array.prototype.slice.call(arguments, 1);
//2.return一个函数
return function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs);
}
}
//使用实例
function add(num1, num2) {
return num1 + num2;
}
/**
curry(add, 5): arguments[0] = fn = add, argumens[1] = 5
args = [5];
curryAdd: return function() { ... }
*/
var curryAdd = curry(add, 5);
/**
curryAdd(2, 3): innerArgs = [2 ,3]
finalArgs = [5, 2, 3]
*/
console.log(curryAdd(2, 3)); //7, 因为add只接收2个参数,所以5,2入参了,3没有入参
//或者一次性给出所有参数
var curryAddAll = curry(add, 5, 12);
console.log(curryAddAll()); // 17
ES6:
//使用了destructuring代替了箭头函数没有arguments内置对象
function currying(fn, ...args) {
//一个闭包
let outerArgs = [...args];
const returnFn = (...newArgs) => {
const finalArgs = [...outerArgs, ...newArgs]; return fn(...finalArgs); };
//返回一个函数
return returnFn;}
// 用法如下:
const add3 = (a, b, c) => a + b + c;
const curryAdd3 = currying(add3, 1);
console.log(curryAdd3(2,3)); // 6
使用柯里化手写其他函数
防抖函数
原理:触发事件,但是在事件触发 n 秒后才执行,如果在一个事件触发的 n 秒内又触发了这个事件,就以新的事件的时间为准,n 秒后才执行,总之,就是要等触发完事件 n 秒内不再触发事件,才执行实际的函数。
触发时间以最后一次触发为准。
<!DOCTYPE html>
<html lang="en">
<head>
<title>防抖</title>
<meta charset="utf-8" />
</head>
<body>
<button id="submit-btn">提交</button>
</body>
<script>
function submit() {
console.log("submit");
}
/**
1. 创建一个setTimeout()的闭包变量timer
2. return 一个函数
3. return函数内,如果setTimeout()未清空,就clearTimeout()
4. timer = setTimeout(() => {...})
*/
const debounce = (fn, delay) => {
let timer = null; //一个闭包
return (...args) => { //return 一个函数
if (timerId) {
window.clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
};
};
const btnDebounce = debounce(submit, 1000);
const btn = document.getElementById("submit-btn");
btn.addEventListener("click", btnDebounce);
</script>
</html>
节流函数
原理:连续触发事件,在时间间隔内,只执行一次事件。触发时间以第一次触发为准。
<!DOCTYPE html>
<html lang="en">
<head>
<title>节流</title>
<meta charset="utf-8" />
</head>
<body>
<button id="submit-btn">提交</button>
</body>
<script>
function submit() {
console.log("submit");
}
/**
*/
const throttle = (fn, delay) => {
let canUse = true; //设置一个是否可用的闭包flag
return (...args) => {
if (canUse) {
fn.apply(this, args); //立即执行这个函数
canUse = false;
setTimeout(() => (canUse = true), delay); //在delay毫秒后,再次可用
}
};
};
// 间隔设为3秒,效果比较明显
const btnThrottle = throttle(submit, 3000);
const btn = document.getElementById("submit-btn");
btn.addEventListener("click", btnThrottle);
</script>
</html>