根据一段代码浅谈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 相关文章推荐
prototype 的说明 js类
Sep 07 Javascript
运用JQuery的toggle实现网页加载完成自动弹窗
Mar 18 Javascript
jquery中的ajax方法怎样通过JSONP进行远程调用
May 04 Javascript
javascript获取select值的方法分析
Jul 02 Javascript
JavaScript中Textarea滚动条不能拖动的解决方法
Dec 15 Javascript
将JSON字符串转换成Map对象的方法
Nov 30 Javascript
html判断当前页面是否在iframe中的实例
Nov 30 Javascript
ES6新特性五:Set与Map的数据结构实例分析
Apr 21 Javascript
jQuery位置选择器用法实例分析
Jun 28 jQuery
jquery树形插件zTree高级使用详解
Aug 16 jQuery
Element Dropdown下拉菜单的使用方法
Jul 26 Javascript
jQuery实现可以计算进制转换的计算器
Oct 19 jQuery
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/04 冲泡冲煮
关于IIS php调用com组件的权限问题
2012/01/11 PHP
php并发对MYSQL造成压力的解决方法
2013/02/21 PHP
javascript URL锚点取值方法
2009/02/25 Javascript
取选中的radio的值
2010/01/11 Javascript
jQuery 创建Dom元素
2010/05/07 Javascript
Jquery弹出窗口插件 LeanModal的使用方法
2012/03/10 Javascript
Extjs4中Form的使用之本地hiddenfield
2013/11/26 Javascript
JQuery遍历json数组的3种方法
2014/11/08 Javascript
jQuery的中 is(':visible') 解析及用法(必看)
2017/02/12 Javascript
在Angular中使用JWT认证方法示例
2018/09/10 Javascript
jquery层次选择器的介绍
2019/01/18 jQuery
微信小程序上线发布流程图文详解
2019/05/06 Javascript
轻松学习JavaScript函数中的 Rest 参数
2019/05/30 Javascript
vue-video-player 断点续播的实现
2021/02/01 Vue.js
[54:47]Liquid vs VP Supermajor决赛 BO 第五场 6.10
2018/07/05 DOTA
利用Fn.py库在Python中进行函数式编程
2015/04/22 Python
Python中super()函数简介及用法分享
2016/07/11 Python
python用BeautifulSoup库简单爬虫实例分析
2018/07/30 Python
Django工程的分层结构详解
2019/07/18 Python
python 字符串常用函数详解
2019/09/11 Python
python多进程(加入进程池)操作常见案例
2019/10/21 Python
基于TensorFlow中自定义梯度的2种方式
2020/02/04 Python
Python读取VOC中的xml目标框实例
2020/03/10 Python
python 异步async库的使用说明
2020/05/04 Python
python实现经纬度采样的示例代码
2020/12/10 Python
HTML5 通信API 跨域门槛将不再高、数据推送也不再是梦
2013/04/25 HTML / CSS
Debenhams百货英国官方网站:Debenhams UK
2016/07/12 全球购物
巴西宠物店在线:Geração Pet
2017/05/31 全球购物
Linux如何修改文件和文件夹的权限
2013/09/05 面试题
学校文明单位申报材料
2014/05/06 职场文书
公司领导班子对照检查存在问题整改措施
2014/10/02 职场文书
工作简报格式范文
2015/07/21 职场文书
解决Nginx 配置 proxy_pass 后 返回404问题
2021/03/31 Servers
在JavaScript中如何使用宏详解
2021/05/06 Javascript
浅谈Java实现分布式事务的三种方案
2021/06/11 Java/Android