博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript 闭包
阅读量:6399 次
发布时间:2019-06-23

本文共 3695 字,大约阅读时间需要 12 分钟。

目录

定义

引子

闭包的用途

一个常见错误

 

 

 


定义

闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境

引子

首先看一个例子

1
2
3
4
5
6
7
8
9
function 
makeFunc() {
var 
name = 
"Mozilla"
;
function 
displayName() {
alert(name);
}
return 
displayName;
}
var 
myFunc = makeFunc();
myFunc();

这段代码看起来别扭却能正常运行。通常,函数中的局部变量仅在函数的执行期间可用。一旦 makeFunc() 执行过后,我们会很合理的认为 name 变量将不再可用。不过,既然代码运行的没问题,显然不是我们想象的那样。在我们的例子中,myFunc 是一个闭包,由 displayName 函数和闭包创建时存在的 "Mozilla" 字符串形成。

这就是闭包,我们在返回函数的时候,也将函数的环境一并返回了。

闭包的用途

  1. 响应事件而执行的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<
html
>
<
head
>
<
script 
type
=
"text/javascript"
>
function makeSizer(size){
return function(){
document.body.style.fontSize=size+"px";
}
}
var size12= makeSizer(12);
var size14= makeSizer(14);
var size16= makeSizer(16);
window.onload=function(){
document.getElementById("a12").onclick=size12;
document.getElementById("a14").onclick=size14;
document.getElementById("a16"). name="a12" id="a12">12</
a
>
<
a 
name
=
"a12" 
id
=
"a14"
>14</
a
>
<
a 
name
=
"a12" 
id
=
"a16"
>16</
a
>
</
body
>
</
html
>

 2.  模拟似有方法

诸如 Java 在内的一些语言支持将方法声明为私有的,既它们只能被同一个类中的其它方法所调用。

对此,JavaScript 并不提供原生的支持,但是可以使用闭包模拟私有方法。私有方法不仅仅有利于限制对代码的访问:还提供了管理全局命名空间的强大能力,避免非核心的方法弄乱了代码的公共接口部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script type=
"text/javascript"
>
function 
MyObject(){
var 
name=
""
;
return 
{
getName:
function
(){
return 
name;
},
setName:
function
(str){
name=str;
}
}
}
var 
mo = MyObject();
mo.setName(
"Mo1"
);
alert(mo.getName());
//Mo1
alert(mo.name);
//undefined
</script>

在上面的例子中,name作为私有属性,getName,setName为公有方法。

 

一个常见的错误

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
<
html
>
<
head
>
</
head
>
<
body
>
<
p 
id
=
"help"
>Helpful notes will appear here</
p
>
<
p
>E-mail: <
input 
type
=
"text" 
id
=
"email" 
name
=
"email"
></
p
>
<
p
>Name: <
input 
type
=
"text" 
id
=
"name" 
name
=
"name"
></
p
>
<
p
>Age: <
input 
type
=
"text" 
id
=
"age" 
name
=
"age"
></
p
>
<
script 
type
=
"text/javascript"
>
function showHelp(help) {
document.getElementById('help').innerHTML = help;
}
function setupHelp() {
var helpText = [
{'id': 'email', 'help': 'Your e-mail address'},
{'id': 'name', 'help': 'Your full name'},
{'id': 'age', 'help': 'Your age (you must be over 16)'}
];
for (var i = 0; i < 
helpText.length
; i++) {
var 
item 
helpText
[i];
document.getElementById(item.id)
.onfocus 
function
() {
showHelp(item.help);//item.help 为最后一个对象的help
}
}
}
setupHelp();
</script>
</
body
>
</
html
>

该问题的原因在于赋给 onfocus 的函数是闭包;它们由函数定义和记录自 setupHelp 函数作用域的环境构成。一共创建了三个闭包,但是它们都共享同一个环境。在 onfocus 的回调被执行时,循环早已经完成,且此时 item 变量(由所有三个闭包所共享)已经指向了 helpText 列表中的最后一项。

 

修正

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
<
html
>
<
head
>
</
head
>
<
body
>
<
p 
id
=
"help"
>Helpful notes will appear here</
p
>
<
p
>E-mail: <
input 
type
=
"text" 
id
=
"email" 
name
=
"email"
></
p
>
<
p
>Name: <
input 
type
=
"text" 
id
=
"name" 
name
=
"name"
></
p
>
<
p
>Age: <
input 
type
=
"text" 
id
=
"age" 
name
=
"age"
></
p
>
<
script 
type
=
"text/javascript"
>
function showHelp(help) {
document.getElementById('help').innerHTML = help;
}
function makeHelpCallback(help){
return function(){
showHelp(help);
}
}
function setupHelp() {
var helpText = [
{'id': 'email', 'help': 'Your e-mail address'},
{'id': 'name', 'help': 'Your full name'},
{'id': 'age', 'help': 'Your age (you must be over 16)'}
];
for (var i = 0; i < 
helpText.length
; i++) {
var 
item 
helpText
[i];
document.getElementById(item.id)
.onfocus 
=
makeHelpCallback
(item.help);
}
}
setupHelp();
</script>
</
body
>
</
html
>

这段代码可以如我们所期望的那样工作。所有的回调不再共享同一个环境, makeHelpCallback 函数为每一个回调创建一个新的环境。在这些环境中,help 指向 helpText 数组中对应的字符串。

 

本文转自 randy_shandong 51CTO博客,原文链接:http://blog.51cto.com/dba10g/1357820,如需转载请自行联系原作者

你可能感兴趣的文章
理解Android编译命令
查看>>
Snap业务模式存重大缺陷 无法通过规模经济获益
查看>>
迎接平价时代,光伏逆变器的行业演进和格局
查看>>
不知不觉间,OCP对数据中心和云计算基础架构产生了深远的影响
查看>>
首席信息官将被首席数据官取代?
查看>>
网络电话前途暗淡?那你就错了!
查看>>
如何打造优雅工具?Facebook有这四项商业设计原则
查看>>
智能家居行业“身陷囹圄” 企业内外兼修谋发展
查看>>
大数据时代:机器翻译能否取代人工
查看>>
物联网WiFi芯片“爆发式”增长的原因
查看>>
现代数据中心需要保持最佳实践
查看>>
《CATIA V5 从入门到精通(第二版)》——2.6 通用的工具(Tools)
查看>>
《vSphere性能设计:性能密集场景下CPU、内存、存储及网络的最佳设计实践》一1.5.1 虚拟机可扩展性...
查看>>
《实施Cisco统一通信管理器(CIPT1)》一2.1 本章主题
查看>>
《电子基础与维修工具核心教程》——导读
查看>>
《微信公众平台开发:从零基础到ThinkPHP5高性能框架实践》——第2章 本地开发环境搭建及程序开发基础 2.1 本地开发环境的搭建...
查看>>
互联网人出游必备清单
查看>>
Golang环境搭建
查看>>
《程序员的呐喊》一一1.5 作者手记:神秘机器的笔记
查看>>
《AutoCAD 2013中文版从入门到精通》——1.3 配置绘图系统
查看>>