根据一段代码浅谈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防止DIV布局滚动时闪动的解决方法
Oct 30 Javascript
动态生成的DOM不会触发onclick事件的原因及解决方法
Aug 06 Javascript
Mongoose学习全面理解(推荐)
Jan 21 Javascript
Vue2.0实现将页面中表格数据导出excel的实例
Aug 09 Javascript
解决JQuery全选/反选第二次失效的问题
Oct 11 jQuery
详解vue-admin和后端(flask)分离结合的例子
Feb 12 Javascript
JavaScript变量声明var,let.const及区别浅析
Apr 23 Javascript
vue.js实现会动的简历(包含底部导航功能,编辑功能)
Apr 08 Javascript
vue中实现高德定位功能
Dec 03 Javascript
详解vue中v-bind:style效果的自定义指令
Jan 21 Javascript
关于Vue中$refs的探索浅析
Nov 05 Javascript
Ajax实现局部刷新的方法实例
Mar 31 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 session 错误
2009/05/21 PHP
PHP执行批量mysql语句的解决方法
2013/05/02 PHP
php用户注册信息验证正则表达式
2015/11/12 PHP
PHP中__autoload和Smarty冲突的简单解决方法
2016/04/08 PHP
javascript同步Import,同步调用外部js的方法
2008/07/08 Javascript
firefox浏览器不支持innerText的解决方法
2013/08/07 Javascript
JS Replace 全部替换字符的用法小结
2013/12/24 Javascript
Jquery 监视按键,按下回车键触发某方法的实现代码
2014/05/11 Javascript
JS实现可调整倒计时间代码分享
2015/08/18 Javascript
详解JS中Array对象扩展与String对象扩展
2016/01/07 Javascript
AngularJS向后端ASP.NET API控制器上传文件
2016/02/03 Javascript
JavaScript学习笔记之创建对象
2016/03/25 Javascript
滚动条的监听与内容随着滚动条动态加载的实现
2017/02/08 Javascript
Bootstrap如何激活导航状态
2017/03/22 Javascript
vue2 前后端分离项目ajax跨域session问题解决方法
2017/04/27 Javascript
Angular路由ui-router配置详解
2018/08/01 Javascript
通过函数作用域和块级作用域看javascript的作用域链
2018/08/05 Javascript
微信小程序实现自动定位功能
2018/10/31 Javascript
vue 解决provide和inject响应的问题
2020/11/12 Javascript
node中短信api实现验证码登录的示例代码
2021/01/20 Javascript
python根据出生年份简单计算生肖的方法
2015/03/27 Python
Python解析树及树的遍历
2016/02/03 Python
Python面向对象编程基础实例分析
2020/01/17 Python
pyinstaller 3.6版本通过pip安装失败的解决办法(推荐)
2020/01/18 Python
Tensorflow 卷积的梯度反向传播过程
2020/02/10 Python
Pandas读取csv时如何设置列名
2020/06/02 Python
pycharm 实现本地写代码,服务器运行的操作
2020/06/08 Python
Python 如何查找特定类型文件
2020/08/17 Python
H&M旗下高端女装品牌:& Other Stories
2018/05/07 全球购物
印尼最大的网上书店:Gramedia.com
2018/09/13 全球购物
如何写毕业求职自荐信
2013/11/06 职场文书
电子信息专业学生自荐信
2013/11/09 职场文书
夜大毕业生自我评价分享
2013/11/10 职场文书
医学生临床实习自我评价
2014/03/07 职场文书
python绘制箱型图
2021/04/27 Python
Golang 遍历二叉树
2022/04/19 Golang