写在前面
什么是闭包?闭包有什么作用?这是我遇到闭包时的第一反应。
闭包在JavaScript高级程序设计(第3版)中是这样描述:闭包是指有权访问另一个函数作用域中的变量的函数。
那么闭包的作用也就很明显了:
- 可以在函数的外部访问到函数内部的局部变量。
- 让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。
1.让函数只执行一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function once(fn) { let flag = false; return function() { if (!flag) { flag = true; fn.apply(this, arguments); } } }
function log() { console.log(12306); }
let c = once(log) c() c() c()
|
上述代码只输出一次12306,利用闭包达到了让函数只执行一次的效果。
2. 函数柯里化
函数柯里化有以下几种版本:
1 2 3 4 5 6 7 8 9 10 11 12 13
| function curry(fn, ...args) { return function () { let _args = [...arguments] if (args !== undefined) { _args = [...args, ..._args] } if (_args.length < fn.length) { curry(fn, _args) } else { fn.apply(null, _args) } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| function curry(fn) { const arg1 = [...arguments].slice(1) return function curried() { if (fn.length - arguments.length <= arg1.length) { const args = [...arg1, ...arguments] return fn.apply(null, args) } else { return (...arg) => curried(...arguments, ...arg) } } }
|
1 2 3 4 5 6 7 8
| function curry(fn) { let judge = (...args) => { if (args.length == fn.length) return fn(...args) return (...arg) => judge(...args, ...arg) } return judge }
|
1 2 3 4 5 6 7 8 9 10 11 12
| function Curry(fn) { const arg1 = [...arguments].slice(1) return function fn2() { if (fn.length - arguments.length <= arg1.length) { const args = [...arg1, ...arguments] return () => fn(...args) } else { return (...arg) => fn2(...arguments, ...arg) } } }
|
3. 函数节流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function throttle(fn, ctx = null, duration = 2000) { let startTime = 0, first = true return function () { if (first) { first = false return } let endTime = Date.now() if (endTime - startTime >= duration) { fn.apply(ctx, arguments) startTime = endTime } } }
function fn(e) { console.log(e.type, 777) }
let cd = throttle(fn) window.onscroll = cd
|
4. 函数防抖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function debounce(fn, ctx = null, delay = 2000) { let timer = null return function () { if (timer) clearTimeout(timer) timer = setTimeout(() => { fn.apply(ctx, arguments) }, delay) } }
function fn(e) { console.log(e.type, 3333) }
let cc = debounce(fn)
window.onresize = cc
|