根据一段代码浅谈Javascript闭包


Posted in Javascript onDecember 14, 2010
function f1(){ 
var n = 999; 
nAdd = function(){ n += 1; } 
function f2(){ 
alert(n); 
} 
return f2; 
}

这里的闭包是f1,封闭了一个变量n和一个函数f2。

我们先无视nAdd,尽量保持原貌重写一下这个函数。

function f1(){ 
var n = 999; 
var f2 = function(){ alert(n); }; 
return f2; 
} 
var result = f1(); 
result();

js中各个变量以function为单元进行封装,当在function内部找不到某一变量时,function会向其所在的上一单元(上下文)中进行查找,一直查找到顶层的window域。
这时就出现一个疑问:这个查找过程是以函数引用位置为起点还是函数体定义的位置为起点?
在上面这一段代码中,result所在域是window,但是实际的输出结果是f1内部的n值,所以可以得出结论:变量查找的起点是函数体定义的位置。

现在再回过头来看nAdd(第一段代码)。如我们所知,没有关键字var定义的变量默认进入window域,所以nAdd实际为window.nAdd。这就等同于如下代码:

var nAdd; 
function f1(){ 
var n = 999; 
nAdd = function(){ n += 1; } 
function f2(){ 
alert(n); 
} 
return function(){ alert(n); }; 
}

那么根据我们对result的分析,nAdd的执行将影响f1中n的值。
所以有:
function f1(){ 
var n = 999; 
nAdd = function(){ n += 1; } 
function f2(){ 
alert(n); 
} 
return function(){ alert(n); }; 
} 
var result = f1(); 
result(); 
nAdd(); 
result();

这段代码执行最终的输出结果为1000。

再看这种情况:

function f1(){ 
var n = 999; 
nAdd = function(){ n += 1; } 
function f2(){ 
alert(n); 
} 
return function(){ alert(n); }; 
} f1()(); //<--p1 
nAdd(); 
f1()(); //<--p2

简述一下执行过程:
p1位置,f1封装了一个匿名的闭包A,在返回A闭包中的函数A:f2后继而执行A:f2,A:f2输出变量A:n,结果是999。
与此同时,nAdd被赋值为A闭包中的一个函数,下一行执行nAdd即让A:n的值+1。
p2位置,f1封装匿名的闭包B,所进行的操作都是针对闭包B的,随后执行B:f2输出的是B:n,所以最后的结果依然是999。
A和B是两个独立的“包”,互不影响。

改写一下函数的调用部分:

function f1(){ 
var n = 999; 
nAdd = function(){ n += 1; } 
function f2(){ 
alert(n); 
} 
return function(){ alert(n); }; 
} var result = f1(); 
result(); 
nAdd(); 
f1()(); 
result(); // <--p3

p3位置不意外地输出了1000。
Javascript 相关文章推荐
js小技巧--自动隐藏红叉叉
Aug 13 Javascript
JQuery 学习笔记 选择器之四
Jul 23 Javascript
jQuery 表单验证扩展(四)
Oct 20 Javascript
一些主流JS框架中DOMReady事件的实现小结
Feb 12 Javascript
JS按位非(~)运算符与~~运算符的理解分析
Jul 31 Javascript
jQuery EasyUI学习教程之datagrid点击列表头排序
Jul 09 Javascript
JavaScript获取当前时间向前推三个月的方法示例
Feb 04 Javascript
微信小程序实现导航栏选项卡效果
Jun 19 Javascript
jQuery阻止事件冒泡实例分析
Jul 03 jQuery
vue中如何实现pdf文件预览的方法
Jul 12 Javascript
JavaScript中arguments和this对象用法分析
Aug 08 Javascript
vue-cli3 取消eslint校验代码的解决办法
Jan 16 Javascript
js保存当前路径(cookies记录)
Dec 14 #Javascript
利用JQuery的load函数动态加载其它页面的内容的实现代码
Dec 14 #Javascript
Jquery练习之表单验证实现代码
Dec 14 #Javascript
基于Jquery的淡入淡出的特效基础练习
Dec 13 #Javascript
Juqery Html(),append()等方法的Bug解决方法
Dec 13 #Javascript
JQuery中getJSON的使用方法
Dec 13 #Javascript
JavaScript 学习历程和心得分享
Dec 12 #Javascript
You might like
中国的第一台收音机
2021/03/01 无线电
Windows下的PHP安装文件线程安全和非线程安全的区别
2014/04/23 PHP
Thinkphp搭建包括JS多语言的多语言项目实现方法
2014/11/24 PHP
ThinkPHP连接Oracle数据库
2016/04/22 PHP
thinkphp3.2.0 setInc方法 源码全面解析
2018/01/29 PHP
ThinkPHP5.0 图片上传生成缩略图实例代码说明
2018/06/20 PHP
针对PHP开发安全问题的相关总结
2019/03/22 PHP
用javascript实现在小方框中浏览大图的代码
2007/08/14 Javascript
JS正则表达式验证数字代码
2014/01/28 Javascript
ES5学习教程之Array对象
2017/04/01 Javascript
Angular中ng-repeat与ul li的多层嵌套重复问题
2017/07/24 Javascript
如何抽象一个Vue公共组件
2017/10/17 Javascript
微信小程序出现wx.navigateTo页面不跳转问题的解决方法
2017/12/26 Javascript
写一个移动端惯性滑动&amp;回弹Vue导航栏组件 ly-tab
2018/03/06 Javascript
微信小程序 搜索框组件代码实例
2019/09/06 Javascript
微信小程序换肤功能实现代码(思路详解)
2020/08/25 Javascript
解决antd Form 表单校验方法无响应的问题
2020/10/27 Javascript
[02:36]DOTA2亚洲邀请赛小组赛精彩集锦:EE凭借法力虚空拿下4杀
2017/03/30 DOTA
[53:29]完美世界DOTA2联赛循环赛 DM vs Matador BO2第二场 11.04
2020/11/05 DOTA
Python制作CSDN免积分下载器
2015/03/10 Python
python实现数值积分的Simpson方法实例分析
2015/06/05 Python
解决PyCharm同目录下导入模块会报错的问题
2018/10/13 Python
python 计算平均平方误差(MSE)的实例
2019/06/29 Python
使用coverage统计python web项目代码覆盖率的方法详解
2019/08/05 Python
Python GUI库PyQt5样式QSS子控件介绍
2020/02/25 Python
python GUI库图形界面开发之PyQt5输入对话框QInputDialog详细使用方法与实例
2020/02/27 Python
诺心蛋糕官网:LE CAKE
2018/08/25 全球购物
优质美利奴羊毛袜,不只是徒步旅行:Darn Tough Vermont
2018/11/05 全球购物
英国在线照明超市:Castlegate Lights
2019/10/30 全球购物
工作鉴定评语
2014/05/04 职场文书
投标承诺书怎么写
2014/05/24 职场文书
本溪关门山导游词
2015/02/09 职场文书
大学生学年个人总结
2015/02/15 职场文书
现货白银电话营销话术
2015/05/29 职场文书
python中出现invalid syntax报错的几种原因分析
2022/02/12 Python
多台电脑共享文件怎么设置?多台电脑共享文件操作教程
2022/04/08 数码科技