根据一段代码浅谈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 相关文章推荐
eval与window.eval的差别分析
Mar 17 Javascript
利用jQuary实现文字浮动提示效果示例代码
Dec 26 Javascript
js清空表单数据的两种方式(遍历+reset)
Jul 18 Javascript
利用jquery制作滚动到指定位置触发动画
Mar 26 Javascript
div实现自适应高度的textarea实现angular双向绑定
Jan 08 Javascript
基于JavaScript实现焦点图轮播效果
Mar 27 Javascript
React组件生命周期详解
Jul 03 Javascript
vue2.0实现移动端的输入框实时检索更新列表功能
May 08 Javascript
详解Axios统一错误处理与后置
Sep 26 Javascript
el-select 下拉框多选实现全选的实现
Aug 02 Javascript
Vue element-ui父组件控制子组件的表单校验操作
Jul 17 Javascript
处理JavaScript值为undefined的7个小技巧
Jul 28 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断点续传之如何分割合并文件
2014/03/22 PHP
PHP获取二维数组中某一列的值集合
2015/12/25 PHP
redirect_uri参数错误的解决方法(必看)
2017/02/16 PHP
详解cookie验证的php应用的一种SSO解决办法
2017/10/20 PHP
改版了网上的一个js操作userdata
2007/04/27 Javascript
关于JavaScript的with 语句的使用方法
2011/05/09 Javascript
js实现图片旋转的三种方法
2014/04/10 Javascript
Jquery树插件zTree用法入门教程
2015/02/17 Javascript
如何防止JavaScript自动插入分号
2015/11/05 Javascript
AngularJS 日期格式化详解
2015/12/23 Javascript
基于Bootstrap+jQuery.validate实现表单验证
2016/05/30 Javascript
H5实现仿flash效果的实现代码
2017/09/29 Javascript
node实现的爬虫功能示例
2018/05/04 Javascript
命令行批量截图Node脚本示例代码
2019/01/25 Javascript
React 组件渲染和更新的实现代码示例
2019/02/21 Javascript
详解vue中this.$emit()的返回值是什么
2019/04/07 Javascript
vue常用高阶函数及综合实例
2021/02/25 Vue.js
python实现上传样本到virustotal并查询扫描信息的方法
2014/10/05 Python
使用Python写一个贪吃蛇游戏实例代码
2017/08/21 Python
Python协程的用法和例子详解
2017/09/09 Python
python实现指定文件夹下的指定文件移动到指定位置
2018/09/17 Python
Python变量、数据类型、数据类型转换相关函数用法实例详解
2020/01/09 Python
Tensorflow训练MNIST手写数字识别模型
2020/02/13 Python
Jupyter Notebook安装及使用方法解析
2020/11/12 Python
Zatchels官网:英国剑桥包品牌
2021/01/12 全球购物
strstr()的简单实现
2013/09/26 面试题
Java语言程序设计测试题选择题部分
2014/04/03 面试题
求职简历自荐信范文
2013/10/21 职场文书
公务员综合考察材料
2014/02/01 职场文书
九一八事变演讲稿范文
2014/09/14 职场文书
公务员群众路线心得体会
2014/11/03 职场文书
2015年南京大屠杀纪念日活动总结
2015/03/24 职场文书
统计员岗位职责范本
2015/04/14 职场文书
劳动仲裁撤诉申请书
2015/05/18 职场文书
迎新晚会主持词开场白
2015/05/28 职场文书
浅谈MySql update会锁定哪些范围的数据
2022/06/25 MySQL