浅谈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 相关文章推荐
ajax请求乱码的解决方法(中文乱码)
Apr 10 Javascript
BootStrap实用代码片段之一
Mar 22 Javascript
D3.js实现折线图的方法详解
Sep 21 Javascript
JavaScript实现url参数转成json形式
Sep 25 Javascript
浅谈javascript控制HTML5的全屏操控,浏览器兼容的问题
Oct 10 Javascript
对javascript继承的理解
Oct 11 Javascript
怎样判断jQuery当前元素是隐藏还是显示
Nov 23 Javascript
用headjs来管理和加载js 提高网站加载速度
Nov 29 Javascript
jQuery实现圣诞节礼物传送(花式轮播)
Dec 25 Javascript
详解javascript立即执行函数表达式IIFE
Feb 13 Javascript
js学习总结之DOM2兼容处理顺序问题的解决方法
Jul 27 Javascript
layui的表单验证支持ajax判断用户名是否重复的实例
Sep 06 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
WML,Apache,和 PHP 的介绍
2006/10/09 PHP
探讨:使用XMLSerialize 序列化与反序列化
2013/06/08 PHP
如何阻止网站被恶意反向代理访问(防网站镜像)
2014/03/18 PHP
PHP函数shuffle()取数组若干个随机元素的方法分析
2016/04/02 PHP
php指定长度分割字符串str_split函数用法示例
2017/01/30 PHP
PHP实现在windows下配置sendmail并通过mail()函数发送邮件的方法
2017/06/20 PHP
PHP设计模式(三)建造者模式Builder实例详解【创建型】
2020/05/02 PHP
js控制滚动条缓慢滚动到顶部实现代码
2013/03/20 Javascript
Javascript验证Visa和MasterCard信用卡号的方法
2015/07/27 Javascript
基于javascript代码实现通过点击图片显示原图片
2015/11/29 Javascript
精通JavaScript的this关键字
2020/05/28 Javascript
深入理解关于javascript中apply()和call()方法的区别
2016/04/12 Javascript
微信小程序 实例应用(记账)详解
2016/09/28 Javascript
jQuery实现按比例缩放图片的方法
2017/04/29 jQuery
Angular.JS中指令ng-if、ng-show/ng-hide和ng-switch的使用教程
2017/05/07 Javascript
基于vue实现swipe分页组件实例
2017/05/25 Javascript
浅谈JS获取元素的N种方法及其动静态讨论
2017/08/25 Javascript
详解JSONObject和JSONArray区别及基本用法
2017/10/25 Javascript
vue 自定义全局方法,在组件里面的使用介绍
2018/02/28 Javascript
小程序组件之自定义顶部导航实例
2019/06/12 Javascript
如何换个角度使用VUE过滤器详解
2019/09/11 Javascript
Vue使用vue-draggable 插件在不同列表之间拖拽功能
2020/03/12 Javascript
在webstorm中配置less的方法详解
2020/09/25 Javascript
vue组件实现移动端九宫格转盘抽奖
2020/10/16 Javascript
[36:22]VP vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python面向对象总结及类与正则表达式详解
2019/04/18 Python
python实现吃苹果小游戏
2020/03/21 Python
jupyter notebook 调用环境中的Keras或者pytorch教程
2020/04/14 Python
html5标记文字_动力节点Java学院整理
2017/07/11 HTML / CSS
HUGO BOSS美国官方网上商店:世界知名奢侈品牌
2017/08/04 全球购物
Expedia印度:您的一站式在线旅游网站
2017/08/24 全球购物
Loreto Gallo英国:欧洲领先的在线药房
2021/01/21 全球购物
2014年乡镇植树节活动方案
2014/02/28 职场文书
广告设计应届生求职信
2014/03/01 职场文书
开网店计划分析
2019/07/30 职场文书
用python基于appium模块开发一个自动收取能量的小助手
2021/09/25 Python