0%

js闭包

闭包就是能够读取其他函数内部变量的函数。

简介

闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。摘自百度百科

应用

有些时候我们往往会使用全局变量来作为计数容器,这是一个不好的习惯。原因如下:

我们可以使用闭包来代替使用全局变量,具体使用见下边:

比如我们需要实现一个打字机效果,第一次调用的时候正向播放文本,第二次调用的时候逆向播放文本。我们需要使用到一个标志位用于切换两种效果。

首先是实现正、逆切换,函数cut()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
let myflag = true;//此时是一个全局变量
function cut() {
if (myflag) {
for (let i = 1; i <= str.length; i++) { //正放
setTimeout(function() { //定时器
word.innerHTML = str.substr(0, i);
}, (i - 1) * time);
}
} else {
for (let j = str.length; j >= 0; j--) { //倒放
setTimeout(function() { //定时器
word.innerHTML = str.substr(0, j);
}, (str.length - j) * time);
}
}
myflag = !myflag;
}
</script>

实现闭包:

我们将该函数封装在另一个函数play()中,调用play就返回函数cut()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
function play() {
let myflag = true;//此时是一个局部变量
function cut() {
if (myflag) {
for (let i = 1; i <= str.length; i++) { //正放
setTimeout(function() { //定时器
word.innerHTML = str.substr(0, i);
}, (i - 1) * time);
}
} else {
for (let j = str.length; j >= 0; j--) { //倒放
setTimeout(function() { //定时器
word.innerHTML = str.substr(0, j);
}, (str.length - j) * time);
}
}
myflag = !myflag;
}
return cut; //注意不要带上括号
}
</script>

案例

完善打字机案例

下边的内容与闭包没有关系了。使用闭包完善一下案例:打字机效果

  • 再将函数play()封装在一个函数show()中。调用show()函数会播放打字机动画,且返回动画所用时间。
  • 函数play()后边添加调用(执行)play()的部分,根据参数num设置播放次数。num:-1为正放一次,其他数字为正+逆。例如:-1,只正放一次。1,”正+逆“一次。2,”正+逆“两次。
1
2
3
4
5
6
let playFn = play(); //获取实现播放效果的函数
for (let i = 0; i < num; i++) {
setTimeout(function() {
playFn();
}, (str.length * time + timewait) * i);
}

函数show()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//封装好的函数
function show(word, str, num, time, timewait) { //num-1为正放一次,其他数字为正+逆。例如:-1,只正放一次。1,”正+逆“一次。2,”正+逆“两次。
//默认值
if (num == null) {
num = 1 * 2;
} else {
if (num == -1) { //只正放一次
num = 1;
} else {
num *= 2;
}
}
if (time == null) {
time = 200; //每个字符显示的时间
}
if (timewait == null) {
timewait = 2000; //正倒放等待时间
}
//播放(返回一个函数,调用返回的函数执行播放动作。多次调用,先正后逆。)
function play() {
let myflag = true;

function cut() {
if (myflag) {
for (let i = 1; i <= str.length; i++) { //正放
setTimeout(function() { //定时器
word.innerHTML = str.substr(0, i);
}, (i - 1) * time);
}
} else {
for (let j = str.length; j >= 0; j--) { //倒放
setTimeout(function() { //定时器
word.innerHTML = str.substr(0, j);
}, (str.length - j) * time);
}
}
myflag = !myflag;
}
return cut; //注意不要带上括号
}
let playFn = play(); //获取实现播放效果的函数
for (let i = 0; i < num; i++) {
setTimeout(function() {
playFn();
}, (str.length * time + timewait) * i);
}
return (str.length * time + timewait) * num;
}

播放多条文本

根据函数show()返回的动画播放时间,使用嵌套的定时器即可实现播放多条文本的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let word = document.querySelector('.word');//显示文本的容器
let str1 = "hello<br>world<br>!";//可以嵌入html代码
let str2 = "你好,我是码代码的冰果果!";
let str3 = "很高兴见到你。";
let str4 = "测试:我只正放一次!";
let time_wait = 1000;//播放等待时间
setTimeout(function() {
time_wait = show(word, str1, 1); //播放第一句

setTimeout(function() { //第二句
time_wait = show(word, str2, 2);

setTimeout(function() { //第三句
time_wait = show(word, str3, 1);

setTimeout(function() { //第四句
show(word, str4, -1);//只正放一次
}, time_wait);
}, time_wait);
}, time_wait);
}, time_wait);

打字机效果案例源码:https://cloud.189.cn/t/MbYraiArERrq(访问码:hzj6)

若图片不能正常显示,请在浏览器中打开

欢迎关注我的其它发布渠道