浅谈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 相关文章推荐
A标签触发onclick事件而不跳转的多种解决方法
Jun 27 Javascript
extjs render 用法介绍
Sep 11 Javascript
javascript 实现map集合
Apr 03 Javascript
学习JavaScript设计模式(封装)
Nov 26 Javascript
AngularJs表单验证实例详解
May 30 Javascript
url中的特殊符号有什么含义(推荐)
Jun 17 Javascript
详解利用Angular实现多团队模块化SPA开发框架
Nov 27 Javascript
微信小程序实现笑脸评分功能
Nov 03 Javascript
vue组件定义,全局、局部组件,配合模板及动态组件功能示例
Mar 19 Javascript
vue-cli 为项目设置别名的方法
Oct 15 Javascript
深入了解JS之作用域和闭包
Jun 16 Javascript
js实现磁性吸附的示例
Oct 26 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
dedecms模板标签代码官方参考
2007/03/17 PHP
如何让PHP编码更加好看利于阅读
2019/05/12 PHP
许愿墙中用到的函数
2006/10/07 Javascript
动态加载脚本提升javascript性能
2014/02/24 Javascript
JS下载文件|无刷新下载文件示例代码
2014/04/17 Javascript
JavaScript中的公有、私有、特权和静态成员用法分析
2014/11/20 Javascript
浅谈Javascript实现继承的方法
2015/07/06 Javascript
Radio 单选JS动态添加的选项onchange事件无效的解决方法
2016/12/12 Javascript
原生js实现打字动画游戏
2017/02/04 Javascript
JavaScript实现的冒泡排序法及统计相邻数交换次数示例
2017/04/26 Javascript
jQuery实现简单的抽奖游戏
2017/05/05 jQuery
利用forever和pm2部署node.js项目过程
2017/05/10 Javascript
JavaScript 通过Ajax 动态加载CheckBox复选框
2017/08/31 Javascript
vue 1.0 结合animate.css定义动画效果
2018/07/11 Javascript
微信小程序判断用户是否需要再次授权获取个人信息
2019/07/18 Javascript
Vue实现点击按钮复制文本内容的例子
2019/11/09 Javascript
Vue项目接入Paypal实现示例详解
2020/06/04 Javascript
[03:46]DOTA2英雄基础教程 维萨吉
2013/12/11 DOTA
[43:14]Liquid vs Optic 2018国际邀请赛淘汰赛BO3 第二场 8.21
2018/08/22 DOTA
python中实现指定时间调用函数示例代码
2017/09/08 Python
Python + selenium + requests实现12306全自动抢票及验证码破解加自动点击功能
2018/11/23 Python
Django使用中间键实现csrf认证详解
2019/07/22 Python
Django实现网页分页功能
2019/10/31 Python
Manjaro、pip、conda更换国内源的方法
2020/11/17 Python
Django-silk性能测试工具安装及使用解析
2020/11/28 Python
python-地图可视化组件folium的操作
2020/12/14 Python
英国花园药房: The Garden Pharmacy
2017/12/28 全球购物
诺心蛋糕官网:LE CAKE
2018/08/25 全球购物
法院实习人员自我鉴定
2013/09/26 职场文书
大四优秀党员个人民主评议
2014/09/19 职场文书
机电专业毕业生自我鉴定2014
2014/10/04 职场文书
六一儿童节标语
2014/10/08 职场文书
场地使用证明模板
2014/10/25 职场文书
学校远程教育工作总结
2015/08/11 职场文书
vue封装数字翻牌器
2022/04/20 Vue.js
解决ubuntu安装软件时,status-code=409报错的问题
2022/12/24 Servers