写在前面

什么是闭包?闭包有什么作用?这是我遇到闭包时的第一反应。

闭包在JavaScript高级程序设计(第3版)中是这样描述:闭包是指有权访问另一个函数作用域中的变量的函数。

那么闭包的作用也就很明显了:

  1. 可以在函数的外部访问到函数内部的局部变量。
  2. 让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。

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