根据一段代码浅谈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的with语句使用方法
Sep 21 Javascript
js实现进度条的方法
Feb 13 Javascript
10个JavaScript中易犯小错误
Feb 14 Javascript
BootStrap中Tab页签切换实例代码
May 30 Javascript
JS JSOP跨域请求实例详解
Jul 04 Javascript
jQuery实现图片轮播效果代码
Sep 27 Javascript
ES6字符串模板,剩余参数,默认参数功能与用法示例
Apr 06 Javascript
使用Vue写一个datepicker的示例
Jan 27 Javascript
微信小程序用户信息encryptedData详解
Aug 24 Javascript
使用Promise封装小程序wx.request的实现方法
Nov 13 Javascript
vue+koa2搭建mock数据环境的详细教程
May 18 Javascript
js屏蔽F12审查元素,禁止修改页面代码等实现代码
Oct 02 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 过滤器实现代码
2010/08/09 PHP
深入浅出讲解:php的socket通信原理
2016/12/03 PHP
PHP智能识别收货地址信息实例
2019/01/05 PHP
PHP 文件上传限制问题
2019/09/01 PHP
PHP Pipeline 实现中间件的示例代码
2020/04/26 PHP
一个JS翻页效果
2007/07/23 Javascript
通过继承IHttpHandle实现JS插件的组织与管理
2010/07/13 Javascript
jquery中常用的SET和GET$(”#msg”).html循环介绍
2013/10/09 Javascript
javascript使用window.open提示“已经计划系统关机”的原因
2014/08/15 Javascript
jQuery自定义滚动条完整实例
2016/01/08 Javascript
浅谈jQuery中ajaxPrefilter的应用
2016/08/01 Javascript
基于javascript实现的购物商城商品倒计时实例
2016/12/11 Javascript
NodeJS简单实现WebSocket功能示例
2018/02/10 NodeJs
jQuery中图片展示插件highslide.js的简单dom
2018/04/22 jQuery
vue内置组件transition简单原理图文详解(小结)
2018/07/12 Javascript
微信小程序结合Storage实现搜索历史效果
2019/05/18 Javascript
vue-next/runtime-core 源码阅读指南详解
2019/10/25 Javascript
vue实现用户长时间不操作自动退出登录功能的实现代码
2020/07/23 Javascript
javascript实现放大镜功能
2020/12/09 Javascript
vue实现按钮切换图片
2021/01/20 Vue.js
[01:19:46]DOTA2-DPC中国联赛 正赛 SAG vs DLG BO3 第一场 2月28日
2021/03/11 DOTA
Python Mysql自动备份脚本
2008/07/14 Python
Python CSV模块使用实例
2015/04/09 Python
总结Python中逻辑运算符的使用
2015/05/13 Python
Python向日志输出中添加上下文信息
2017/05/24 Python
python3.0 模拟用户登录,三次错误锁定的实例
2017/11/02 Python
Pandas之ReIndex重新索引的实现
2019/06/25 Python
TensorFlow学习之分布式的TensorFlow运行环境
2020/02/05 Python
python实现手势识别的示例(入门)
2020/04/15 Python
keras之权重初始化方式
2020/05/21 Python
美国最大的户外装备和服装购物网站:Backcountry
2019/10/15 全球购物
潘多拉珠宝俄罗斯官方网上商店:PANDORA俄罗斯
2020/09/22 全球购物
了解AppleShare protocol(AppleShare协议)吗
2015/08/28 面试题
应届生幼儿园求职信
2013/11/12 职场文书
运动会稿件100字
2014/09/24 职场文书
Python使用pyecharts控件绘制图表
2022/06/05 Python