深入理解 JS 闭包的 9 大使用场景
1 返回值(最常用)
js1//以闭包的形式将 name 返回。
2function fn() {
3 let name = 'hello'
4 return function() {
5 return name
6 }
7}
8let func = fn() //调用,得到函数
9console.log(func()) //再次调用,输出hello
2 函数赋值
在闭包里面给 fn2 函数设置值,闭包的形式把 name 属性记忆下来,执行会输出 hello
js1let fn2
2function fn() {
3 let name = 'hello'
4 //将函数赋值为fn2
5 fn2 = function() {
6 return name
7 }
8}
9
10fn() // 要先执行进行赋值
11console.log(fn2()) //执行输出fn2,即hello
3 函数参数
用闭包返回一个函数,把此函数作为另一个函数的参数,在另一个函数里面执行这个函数,最终输出 hello
js1function fn() {
2 let name = 'hello'
3 return function callback() {
4 return name
5 }
6}
7
8let fn1 = fn() //执行函数将返回值(callback函数)赋值为fn1
9
10function fn2(f) {
11 //将函数作为参数传入
12 console.log(f()) //执行函数并输出
13}
14
15fn2(fn1) //调用函数
4.IIFE(自执行函数)
直接在自执行函数里面将封装的函数 fn1 传给 fn2,作为参数调用同样可以获得结果 hello
js1;(function() {
2 let name = 'hello'
3 let fn1 = function() {
4 return name
5 }
6 //直接在自执行函数里面调用fn2,将fn1作为参数传入
7 fn2(fn1)
8})()
9
10function fn2(f) {
11 //函数组为参数传入
12 console.log(f()) //执行函数,并输出
13}
5 循环赋值
js1//每秒执行1次,分别输出1-10
2for (let i = 1; i <= 10; i++) {
3 ;(function(j) {
4 setTimeout(function() {
5 console.log(j)
6 }, j * 1000)
7 })(i) //i作为实参传入
8}
6 getter 和 setter
第一次输出 hello 用 setter 以后再输出 world ,这样做可以封装成公共方法,防止不想暴露的属性和函数暴露在外部。
js1function fn() {
2 let name = 'hello'
3 setName = function(n) {
4 name = n
5 }
6 getName = function() {
7 return name
8 }
9
10 //将setName,getName作为对象的属性返回
11 return {
12 setName: setName,
13 getName: getName,
14 //简写
15 //setName,getName
16 }
17}
18let fn1 = fn() //返回对象,属性setName和getName是两个函数
19console.log(fn1.getName()) //getter
20fn1.setName('world') //setter修改闭包里面的name
21console.log(fn1.getName()) //getter
7.迭代器(执行一次函数往下取一个值)
js1let arr = ['aa', 'bb', 'cc']
2function increment(arr) {
3 let i = 0
4 return function() {
5 //这个函数每次被执行都返回数组arr中 i下标对应的元素
6 return arr[i++] || '数组遍历完毕'
7 }
8}
9
10let next = increment(arr)
11console.log(next()) //aa
12console.log(next()) //bb
13console.log(next()) //cc
14console.log(next()) //数组值已经遍历完
8 首次区分(相同的参数,函数不会重复执行)
js1let fn = (function() {
2 let arr = [] //用来缓存的数组
3 return function(val) {
4 if (arr.indexOf(val) == -1) {
5 //缓存中没有则表示需要执行
6 arr.push(val) //将参数push到缓存数组中
7 console.log('函数被执行了', arr)
8 //这里写想要执行的函数
9 } else {
10 console.log('此次函数不需要执行')
11 }
12 console.log('函数调用完打印一下,方便查看已缓存的数组:', arr)
13 }
14})()
15
16fn(10)
17fn(10)
18fn(1000)
19fn(200)
20fn(1000)
执行结果如下:
可以明显的看到首次执行的会被存起来,再次执行直接取。
9 缓存
比如求和操作,如果没有缓存,每次调用都要重复计算,采用缓存已经执行过的去查找,查找到了就直接返回,不需要重新计算
js1let fn = (function() {
2 let cache = {}
3 let calc = function(arr) {
4 let sum = 0
5 for (let i = 0; i < arr.length; i++) {
6 sum += arr[i]
7 }
8 return sum
9 }
10 return function() {
11 let args = Array.prototype.slice.call(arguments, 0)
12 let key = args.join(',')
13 let result,
14 total = cache[key]
15 if (total) {
16 console.log('从缓存中取:', cache) //打印方便查看
17 result = total
18 } else {
19 //重新计算,并存入缓存同时赋值给result
20 result = cache[key] = calc(args)
21 console.log('存入缓存:', cache) //打印方便查看
22 }
23 return result
24 }
25})()
26fn(1, 2, 3, 4, 5)
27fn(1, 2, 3, 4, 5)
28fn(1, 2, 3, 4, 5, 6)
29fn(1, 2, 3, 4, 5, 8)
30fn(1, 2, 3, 4, 5, 6)
输出结果
参考文章
喜欢这篇文章吗?
加载中...
评论
0 条登录后即可参与评论讨论
加载评论中...
相关文章
目录