根据一段代码浅谈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 相关文章推荐
网上应用的一个不错common.js脚本
Aug 08 Javascript
JS 文字符串转换unicode编码函数
May 30 Javascript
jquery一句话全选/取消全选
Mar 01 Javascript
javascript 弹出窗口中是否显示地址栏的实现代码
Apr 14 Javascript
jquery阻止后续事件只执行第一个事件
Jul 24 Javascript
JS简单实现DIV相对于浏览器固定位置不变的方法
Jun 17 Javascript
jQuery事件对象总结
Oct 17 Javascript
html中鼠标滚轮事件onmousewheel的处理方法
Nov 11 Javascript
iscroll-probe实现下拉刷新和下拉加载效果
Jun 28 Javascript
node.js 利用流实现读写同步,边读边写的方法
Sep 11 Javascript
angularjs的单选框+ng-repeat的实现方法
Sep 12 Javascript
addEventListener()和removeEventListener()追加事件和删除追加事件
Dec 04 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
Wordpress 相册插件 NextGEN-Gallery 添加目录将中文转为拼音的解决办法
2010/12/29 PHP
zend api扩展的php对象的autoload工具
2011/04/18 PHP
PHP读取ACCESS数据到MYSQL的代码
2011/05/11 PHP
PHP处理Json字符串解码返回NULL的解决方法
2014/09/01 PHP
类似CSDN图片切换效果脚本
2009/09/17 Javascript
javascript实现获取cookie过期时间的变通方法
2014/08/14 Javascript
让JavaScript和其它资源并发下载的方法
2014/10/16 Javascript
jQuery插件bxSlider实现响应式焦点图
2015/04/12 Javascript
基于JavaScript代码实现pc与手机之间的跳转
2015/12/23 Javascript
JS小数运算出现多为小数问题的解决方法
2016/06/02 Javascript
JavaScript省市区三级联动菜单效果
2016/09/21 Javascript
Bootstrap modal使用及点击外部不消失的解决方法
2016/12/13 Javascript
vuejs父子组件通信的问题
2017/01/11 Javascript
Angular多选、全选、批量选择操作实例代码
2017/03/10 Javascript
ES6中Proxy代理用法实例浅析
2017/04/06 Javascript
关于HTTP传输中gzip压缩的秘密探索分析
2018/01/12 Javascript
vue监听对象及对象属性问题
2018/08/20 Javascript
Vue路由前后端设计总结
2019/08/06 Javascript
基于JS实现视频上传显示进度条
2020/05/12 Javascript
如何利用Node.js与JSON搭建简单的动态服务器
2020/06/16 Javascript
vue-cli3中配置alias和打包加hash值操作
2020/09/04 Javascript
JS中箭头函数与this的写法和理解
2021/01/14 Javascript
[02:58]献给西雅图的情书_高清
2014/05/29 DOTA
全面解读Python Web开发框架Django
2014/06/30 Python
Python标准库之itertools库的使用方法
2017/09/07 Python
使用python将时间转换为指定的格式方法
2018/11/12 Python
使用Python制作一个打字训练小工具
2019/10/01 Python
python+selenium定时爬取丁香园的新型冠状病毒数据并制作出类似的地图(部署到云服务器)
2020/02/09 Python
python 使用elasticsearch 实现翻页的三种方式
2020/07/31 Python
pycharm 关闭search everywhere的解决操作
2021/01/15 Python
TripAdvisor土耳其网站:全球知名旅行社区,真实旅客评论
2017/04/17 全球购物
房屋分割离婚协议书范本
2014/12/01 职场文书
十佳少年事迹材料
2014/12/25 职场文书
小学生作文之《压岁钱的烦恼》
2019/09/27 职场文书
判断Python中的Nonetype类型
2021/05/25 Python
springboot 自定义配置 解决Boolean属性不生效
2022/03/18 Java/Android