根据一段代码浅谈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文件中如何获取basePath处理js路径问题
Jul 10 Javascript
JavaScript中window.showModalDialog()用法详解
Dec 18 Javascript
jQuery中DOM操作实例分析
Jan 23 Javascript
JS实现判断碰撞的方法
Feb 11 Javascript
深入理解JavaScript系列(48):对象创建模式(下篇)
Mar 04 Javascript
Vue.js 2.0 和 React、Augular等其他前端框架大比拼
Oct 08 Javascript
基于require.js的使用(实例讲解)
Sep 07 Javascript
微信、QQ、微博、Safari中使用js唤起App
Jan 24 Javascript
如何理解Vue的v-model指令的使用方法
Jul 19 Javascript
vue 利用路由守卫判断是否登录的方法
Sep 29 Javascript
如何使用vue slot创建一个模态框的实例代码
May 24 Javascript
JavaScript Event Loop相关原理解析
Jun 10 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
php.ini中的php-5.2.0配置指令详解
2008/03/27 PHP
php使用gd2绘制基本图形示例(直线、圆、正方形)
2017/02/15 PHP
详解Laravel设置多态关系模型别名的方式
2019/10/17 PHP
PHP调用QQ互联接口实现QQ登录网站功能示例
2019/10/24 PHP
Javascript this指针
2009/07/30 Javascript
javascript 必知必会之closure
2009/09/21 Javascript
如何从jQuery的ajax请求中删除X-Requested-With
2013/12/11 Javascript
js中使用replace方法完成某个字符的转换
2014/08/20 Javascript
Bootstrap每天必学之折叠(Collapse)插件
2016/04/25 Javascript
BootStrapTable服务器分页实例解析
2016/12/20 Javascript
angular+webpack2实战例子
2017/05/23 Javascript
基于Bootstrap模态对话框只加载一次 remote 数据的解决方法
2017/07/09 Javascript
vue自定义filters过滤器
2018/04/26 Javascript
JS Web Flex弹性盒子模型代码实例
2020/03/10 Javascript
vue中实现拖动调整左右两侧div的宽度的示例代码
2020/07/22 Javascript
浅谈vue 多个变量同时赋相同值互相影响
2020/08/05 Javascript
PHP 502bad gateway原因及解决方案
2020/11/13 Javascript
[01:39](回顾)各路豪强针锋相对,几经鏖战四强产生
2014/07/01 DOTA
使用python解析xml成对应的html示例分享
2014/04/02 Python
Ubuntu 14.04+Django 1.7.1+Nginx+uwsgi部署教程
2014/11/18 Python
Python实现竖排打印传单手机号码易撕条
2015/03/16 Python
详解Python编程中基本的数学计算使用
2016/02/04 Python
Python 实现一个手机号码获取妹子名字的功能
2019/09/25 Python
python使用pymongo与MongoDB基本交互操作示例
2020/04/09 Python
基于python实现音乐播放器代码实例
2020/07/01 Python
PyQt中使用QtSql连接MySql数据库的方法
2020/07/28 Python
销售提升方案
2014/06/07 职场文书
党组织领导班子整改方案
2014/10/25 职场文书
2015年119消防宣传日活动总结
2015/03/24 职场文书
幼儿园家长工作总结2015
2015/04/25 职场文书
入队仪式主持词
2015/07/04 职场文书
2016年中秋祝酒词
2015/11/26 职场文书
CSS3 实现的图片悬停的切换按钮
2021/04/13 HTML / CSS
python中pandas对多列进行分组统计的实现
2021/06/18 Python
十大公认最好看的动漫:《咒术回战》在榜,《钢之炼金术师》第一
2022/03/18 日漫
zabbix配置nginx监控的实现
2022/05/25 Servers