根据一段代码浅谈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 相关文章推荐
document.getElementById方法在Firefox与IE中的区别
May 18 Javascript
javascript中不提供sleep功能如何实现这个功能
May 27 Javascript
JS设置网页图片vspace和hspace属性的方法
Apr 01 Javascript
详解基于javascript实现的苹果系统底部菜单
Dec 02 Javascript
Vue.js基础学习之class与样式绑定
Mar 20 Javascript
swiper移动端轮播插件(触碰图片之后停止轮播)
Dec 28 Javascript
jQuery实现的回车触发按钮事件功能示例
Mar 25 jQuery
详解vue-cli 2.0配置文件(小结)
Jan 14 Javascript
微信小程序中使用Async-await方法异步请求变为同步请求方法
Mar 28 Javascript
微信小程序单选radio及多选checkbox按钮用法示例
Apr 30 Javascript
vue.js实现图书管理功能
Sep 24 Javascript
Websocket 向指定用户发消息的方法
Jan 09 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利用iframe实现无刷新文件上传功能的代码
2011/09/29 PHP
支持中文的php加密解密类代码
2011/11/27 PHP
php一个找二层目录的小东东
2012/08/02 PHP
LotusPhp笔记之:Logger组件的使用方法
2013/05/06 PHP
在Linux系统下一键重新安装WordPress的脚本示例
2015/06/30 PHP
PHP异常处理Exception类
2015/12/11 PHP
php通过header发送自定义数据方法
2018/01/18 PHP
说说掌握JavaScript语言的思想前提想学习js的朋友可以看看
2009/04/01 Javascript
JavaScript 弹出窗体点击按钮返回选择数据的实现
2010/04/01 Javascript
从零开始学习jQuery (十) jQueryUI常用功能实战
2011/02/23 Javascript
javascript动画浅析
2012/08/30 Javascript
Javascript 数组排序详解
2014/10/22 Javascript
jQuery验证插件validation使用指南
2015/04/21 Javascript
微信小程序 实例应用(记账)详解
2016/09/28 Javascript
vue 实现复制内容到粘贴板clipboard的方法
2018/03/17 Javascript
JavaScript实现多态和继承的封装操作示例
2018/08/20 Javascript
微信小程序HTTP接口请求封装的实现
2019/02/21 Javascript
[04:54]DOTA2 2017国际邀请赛:上届冠军WINGS采访短片
2017/08/09 DOTA
[04:00]黄浦江畔,再会英雄——完美世界DOTA2 TI9应援视频
2019/07/31 DOTA
python中函数总结之装饰器闭包详解
2016/06/12 Python
python爬虫之自制英汉字典
2019/06/24 Python
python如何实现异步调用函数执行
2019/07/08 Python
PyCharm中关于安装第三方包的三个建议
2020/09/17 Python
Python 使用office365邮箱的示例
2020/10/29 Python
学会迭代器设计模式,帮你大幅提升python性能
2021/01/03 Python
html5实现滑块功能之type=&quot;range&quot;属性
2020/02/18 HTML / CSS
美国正版电视节目和电影在线观看:Hulu
2018/05/24 全球购物
大学生咖啡店创业计划书
2014/01/21 职场文书
民族团结先进个人材料
2014/02/05 职场文书
岗位职责风险点
2014/03/12 职场文书
总经理助理岗位职责范本
2014/07/20 职场文书
2014年医院后勤工作总结
2014/12/06 职场文书
淘宝好评语句大全
2014/12/31 职场文书
2015年文秘个人工作总结
2015/10/14 职场文书
广告策划的实习心得体会总结!
2019/07/22 职场文书
Go 在 MongoDB 中常用查询与修改的操作
2021/05/07 Golang