根据一段代码浅谈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 相关文章推荐
关于恒等于(===)和非恒等于(!==)
Aug 20 Javascript
window.name代替cookie的实现代码
Nov 28 Javascript
css结合js制作下拉菜单示例代码
Feb 27 Javascript
使用jQuery的attr方法来修改onclick值
Jul 07 Javascript
xmlplus组件设计系列之文本框(TextBox)(3)
May 03 Javascript
js排序与重组的实例讲解
Aug 28 Javascript
node.js中http模块和url模块的简单介绍
Oct 06 Javascript
js实现简单选项卡功能
Mar 23 Javascript
vue服务端渲染添加缓存的方法
Sep 18 Javascript
vue基础知识--axios合并请求和slot
Jun 04 Javascript
Vue看了就会的8个小技巧
Jan 21 Vue.js
js基础语法与maven项目配置教程案例
Jul 15 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函数)
2006/10/09 PHP
从手册去理解分析PHP session机制
2011/07/17 PHP
php获取当前月与上个月月初及月末时间戳的方法
2016/12/05 PHP
数组任意位置插入元素,删除特定元素的实例
2017/03/02 PHP
js 覆盖和重载 函数
2009/09/25 Javascript
TimergliderJS 一个基于jQuery的时间轴插件
2011/12/07 Javascript
asp.net网站开发中用jquery实现滚动浏览器滚动条加载数据(类似于腾讯微博)
2012/03/14 Javascript
jQuery $.get 的妙用 访问本地文本文件
2012/07/12 Javascript
Jquery实现图片左右自动滚动示例
2013/09/25 Javascript
JavaScript中使用stopPropagation函数停止事件传播例子
2014/08/27 Javascript
js简单抽奖代码
2015/01/16 Javascript
深入浅出分析javaScript中this用法
2015/05/09 Javascript
JQuery分屏指示器图片轮换效果实例
2015/05/21 Javascript
基于js实现的限制文本框只可以输入数字
2016/12/05 Javascript
vue如何引入sass全局变量
2018/06/28 Javascript
微信小程序使用for循环动态渲染页面操作示例
2018/12/25 Javascript
解决cordova+vue 项目打包成APK应用遇到的问题
2019/05/10 Javascript
如何使用JavaScript实现栈与队列
2019/06/24 Javascript
JS call()及apply()方法使用实例汇总
2020/07/11 Javascript
[01:24:09]Ti4 冒泡赛第二轮DK vs C9 1
2014/07/14 DOTA
[04:59]DOTA2-DPC中国联赛 正赛 Ehome vs iG 选手采访
2021/03/11 DOTA
python实现绘制树枝简单示例
2014/07/24 Python
python获取一组汉字拼音首字母的方法
2015/07/01 Python
python实现树形打印目录结构
2018/03/29 Python
ITK 实现多张图像转成单个nii.gz或mha文件案例
2020/07/01 Python
解决PyCharm IDE环境下,执行unittest不生成测试报告的问题
2020/09/03 Python
HTML5 canvas标签实现刮刮卡效果
2015/04/24 HTML / CSS
如何保障Web服务器安全
2014/05/05 面试题
财务主管自我鉴定
2014/01/17 职场文书
美丽乡村建设实施方案
2014/03/23 职场文书
工作建议书范文
2014/05/13 职场文书
大学生翘课检讨书范文
2014/10/06 职场文书
团代会邀请函
2015/02/02 职场文书
2015年领导班子工作总结
2015/05/23 职场文书
2016年学生会感恩节活动总结
2016/04/01 职场文书
Linux系统下MySQL配置主从分离的步骤
2022/03/21 MySQL