浅谈JavaScript中的作用域和闭包问题


Posted in Javascript onJuly 07, 2015

JavaScript的作用域以函数为界,不同的函数拥有相对独立的作用域。函数内部可以声明和访问全局变量,也可以声明局部变量(使用var关键字,函数的参数也是局部变量),但函数外部无法访问内部的局部变量:

function test() {
var a = 0; // 局部变量
b = 1; // 全局变量
}
a = ?, b = ? // a为undefined,b为1

同名的局部变量会覆盖全局变量,但本质上它们是两个独立的变量,一方发生变化不会影响另一方:

a = 5; // 函数外a的值为5
function test() {
var a = 4; // 函数内a的值为4
}();
a = ? // 函数外a的值仍为5,不受函数影响

一般而言,函数结束后,对函数内部变量的引用全部结束,函数内的局部变量将被回收,函数的执行环境将被清空,但是,如果以内部函数作为函数的返回结果,情况就会发生变化:

function test(i) {
var b = i * i;
return function() {
return b--;
};
}
var a = test(8);
a(); // 返回值为64, 内部变量b为63
a(); // 返回值为63, 内部变量b为62

当以内部函数作为返回值时,因为函数结束后内部变量的引用并未结束,所以函数的局部变量无法回收,函数的执行环境被保留下来,因而形成了闭包效果,可以通过该引用访问本该被回收的内部变量。
闭包还使得函数的局部变量成为“私有”变量,只能通过返回的内部函数访问,而无法通过其他任何手段去改变。
因此,闭包可用于维持局部变量和保护变量。
不使用闭包的情况:

var a = []; // 假设a中包含5个元素
for (var i = 0, m = a.length; i < m; i++) {
a[i].onclick = function(e) {
return 'No. ' + i;
};
}
// 点击任何一个元素,返回值都是“No. 5”,因为i最后的值为5
使用闭包的情况:
function test(i) {
return function(e) {
return 'No. ' + i;
};
}
var a = []; // 假设a中包含5个元素
for (var i = 0, m = a.length; i < m; i++) {
a[i].onclick = test(i);
}
// 使用闭包维持局部变量,点击元素返回No. 0 ~ No. 4

闭包带来便利的同时,也会带来一些弊端:
1、程序复杂度增加,理解更加困难
2、干扰正常的垃圾回收,复杂的闭包还可能导致内存无法回收而崩溃
3、庞大的闭包往往伴随着性能问题
因此,闭包宜精简小巧,而不宜庞大复杂,同时应避免大规模的使用闭包。闭包的出现,本身是语言的一个bug,但是因为它独特的功能而保留下来。它是一个辅助手段,而不是主要功能。

Javascript 相关文章推荐
JavaScript 事件系统
Jul 22 Javascript
JavaScript 的继承
Oct 01 Javascript
让低版本浏览器支持input的placeholder属性(js方法)
Apr 03 Javascript
非常漂亮的JS+CSS图片幻灯切换特效
Nov 20 Javascript
浅析JavaScript中的typeof运算符
Nov 30 Javascript
倒记时60刷新网页的js代码
Feb 18 Javascript
JQuery.get提交页面不跳转的解决方法
Jan 13 Javascript
JS实现仿新浪微博发布内容为空时提示功能代码
Aug 19 Javascript
jQuery ajax请求返回list数据动态生成input标签,并把list数据赋值到input标签
Mar 29 Javascript
详解使用fetch发送post请求时的参数处理
Apr 05 Javascript
select标签设置默认选中的选项方法
Mar 02 Javascript
原生实现一个react-redux的代码示例
Jun 08 Javascript
深入分析下javascript中的[]()+!
Jul 07 #Javascript
javascript实现的多个层切换效果通用函数实例
Jul 06 #Javascript
javascript动态添加删除tabs标签的方法
Jul 06 #Javascript
Jsonp post 跨域方案
Jul 06 #Javascript
javascript运动详解
Jul 06 #Javascript
浅谈jQuery中height与width
Jul 06 #Javascript
jQuery中$this和$(this)的区别介绍(一看就懂)
Jul 06 #Javascript
You might like
德生S2000收音机更换“钕铁硼”全频扬声器
2021/03/02 无线电
php+mysql分页代码详解
2008/03/27 PHP
php url地址栏传中文乱码解决方法集合
2010/06/25 PHP
PHP Array交叉表实现代码
2010/08/05 PHP
php 创建以UNIX时间戳命名的文件夹(示例代码)
2014/03/08 PHP
smarty中英文多编码字符截取乱码问题解决方法
2014/10/28 PHP
理解php依赖注入和控制反转
2016/05/11 PHP
Yii2处理密码加密及验证的方法
2019/05/12 PHP
PHP上传图片到数据库并显示的实例代码
2019/12/20 PHP
laravel使用数据库测试注意事项
2020/04/10 PHP
用js做一个小游戏平台 (一)
2009/12/29 Javascript
jquery序列化表单去除指定元素示例代码
2014/04/10 Javascript
jQuery的text()方法用法分析
2014/12/20 Javascript
详解 javascript中offsetleft属性的用法
2015/11/11 Javascript
Node.js 条形码识别程序构建思路详解
2016/02/14 Javascript
早该知道的7个JavaScript技巧
2016/06/21 Javascript
Bootstrap三种表单布局的使用方法
2016/06/21 Javascript
jQuery EasyUI datagrid在翻页以后仍能记录被选中行的实现代码
2016/08/15 Javascript
Angular4学习笔记router的简单使用
2018/03/30 Javascript
使用D3.js+Vue实现一个简单的柱形图
2018/08/05 Javascript
解决vue 单文件组件中样式加载问题
2019/04/24 Javascript
JS判断数组里是否有重复元素的方法小结
2019/05/21 Javascript
基于并发服务器几种实现方法(总结)
2017/12/29 Python
urllib和BeautifulSoup爬取维基百科的词条简单实例
2018/01/17 Python
Scrapy框架爬取Boss直聘网Python职位信息的源码
2019/02/22 Python
python selenium 弹出框处理的实现
2019/02/26 Python
使用Python对Dicom文件进行读取与写入的实现
2020/04/20 Python
Philosophy美国官网:美国美容品牌
2016/08/15 全球购物
Peter Alexander新西兰站:澳大利亚领先的睡衣设计师品牌
2016/12/10 全球购物
美国一家全面的在线零售鞋类公司:SHOEBACCA
2017/01/06 全球购物
电大毕业生自我鉴定
2013/11/10 职场文书
银行委托书范本
2014/04/04 职场文书
中学生学雷锋演讲稿
2014/04/26 职场文书
2014年销售工作总结范文
2014/12/01 职场文书
个人先进事迹材料
2014/12/29 职场文书
党风廉洁教育心得体会
2016/01/20 职场文书