根据一段代码浅谈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 相关文章推荐
Javascript MD4
Dec 20 Javascript
关于Mozilla浏览器不支持innerText的解决办法
Jan 01 Javascript
通过js动态操作table(新增,删除相关列信息)
May 23 Javascript
js导航菜单(自写)简单大方
Mar 28 Javascript
jQuery中extend函数的实现原理详解
Feb 03 Javascript
深入理解JavaScript中Ajax
Aug 02 Javascript
JQueryEasyUI之DataGrid数据显示
Nov 23 Javascript
Dropify.js图片宽高自适应的方法
Nov 27 Javascript
vue中使用refs定位dom出现undefined的解决方法
Dec 21 Javascript
基于JS实现html中placeholder属性提示文字效果示例
Apr 19 Javascript
解决vue脚手架项目打包后路由视图不显示的问题
Sep 20 Javascript
浅析vue插槽和作用域插槽的理解
Apr 22 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的call_user_func传reference引发的思考
2010/07/23 PHP
PHP JSON格式数据交互实例代码详解
2011/01/13 PHP
ThinkPHP模板IF标签用法详解
2014/07/01 PHP
php提交过来的数据生成为txt文件
2016/04/28 PHP
php使用pecl方式安装扩展操作示例
2019/08/12 PHP
jQuery 源码分析笔记(6) jQuery.data
2011/06/08 Javascript
移动端JQ插件hammer使用详解
2015/07/03 Javascript
如何解决easyui自定义标签 datagrid edit combobox 手动输入保存不上
2015/12/26 Javascript
JavaScript阻止回车提交表单的方法
2015/12/30 Javascript
jQuery验证表单格式的使用方法
2017/01/10 Javascript
深入探究AngularJs之$scope对象(作用域)
2017/07/20 Javascript
JS实现图片手风琴效果
2020/04/17 Javascript
详解puppeteer使用代理
2018/12/27 Javascript
vue动态绘制四分之三圆环图效果
2019/09/03 Javascript
vue实现购物车的监听
2020/04/20 Javascript
JavaScript Array.flat()函数用法解析
2020/09/02 Javascript
使用beaker让Facebook的Bottle框架支持session功能
2015/04/23 Python
Python实现配置文件备份的方法
2015/07/30 Python
python简单分割文件的方法
2015/07/30 Python
Django自定义插件实现网站登录验证码功能
2017/04/19 Python
python线程池(threadpool)模块使用笔记详解
2017/11/17 Python
python 动态迁移solr数据过程解析
2019/09/04 Python
Python基于pip实现离线打包过程详解
2020/05/15 Python
python实现猜数游戏(保存游戏记录)
2020/06/22 Python
详解python3类型注释annotations实用案例
2021/01/20 Python
英国二手iPhone、音乐、电影和游戏商店:musicMagpie
2018/10/26 全球购物
Desigual美国官方网站:西班牙服装品牌
2019/03/29 全球购物
俄罗斯游戏商店:Buka
2020/03/01 全球购物
上海微创软件面试题
2012/06/14 面试题
体育比赛口号
2014/06/09 职场文书
党员弘扬焦裕禄精神思想汇报
2014/09/10 职场文书
2014入党积极分子破除“四风”思想汇报
2014/09/14 职场文书
幼儿园法制宣传日活动总结
2014/11/01 职场文书
委托书格式要求
2015/01/28 职场文书
Java 将PPT幻灯片转为HTML文件的实现思路
2021/06/11 Java/Android
总结Pyinstaller打包的高级用法
2021/06/28 Python