JavaScript.The.Good.Parts阅读笔记(二)作用域&闭包&减缓全局空间污染


Posted in Javascript onNovember 16, 2010

如代码块

if (true) { 
int i = 100; 
} 
print(i); //错误,变量i没有声明

如上面例子所示,代码块外的函数是无法访问i变量的。
但在javaScript里,情况则完全不同。
if (true) { 
var i = 100; 
} 
alert(i); //弹出框并显示100

很多现代语言都推荐尽可能迟地声明变量,但在Javascript里这是一个最糟糕的建议。由于缺少块级作用域,最好在函数体的顶部声明函数中可能用到的所有变量。

闭包特性:
虽然缺少块级作用域,但是函数的作用域还是存在的。
这种作用域有一个好处,就是内部函数可以访问定义它们的外部函数的参数和变量(除了this和argument)。
利用这种特性,则可以这样来设计代码。

var bankAccount = function () { 
var value = 0; 
return { 
deposit: function (inc) { 
value += inc; 
}, 
getValue: function (){ 
return value; 
} 
} 
} 

var myAccount = bankAccount(); //新开一个银行账户 
myAccount.deposit(1000); //存1000块进去 
alert(myAccount.getValue()); //should alert(1000);

value由于在bankAccount这个function里,外部无法对它进行直接操作,必须通过bankAccount function给他返回的对象来进行操作,通过这样来实现C#和java里的private的字段。

减缓全局变量污染全局空间:利用函数的作用域,我们在写js库的时候可以减少跟其他库冲突。

(function () { 
var hello = 'Hello World.'; 
})(); 
alert(hello); //error: hello no exist.

这里的语法很有点诡异,主要思想是定义一个匿名方法,并且马上执行。由于function开头这个litertal会被解释作为函数定义,这里加上了一对括号包住它,然后再用一对括号表示调用此函数。外部的alert访问不到在函数内部定义的hello。

陷阱一:var的陷阱

“减缓全局变量污染全局空间”的例子改成

(function () { 
hello = 'Hello World.'; //remove var 
})(); 
alert(hello); //alert ('Hello World.');

当变量hello没有用var显式声明时,hello成为了一个全局变量!!

虽然利用这个特性,咱们可以提供一个对外接口,但不建议这样做。

(function () { 
var hello = 'Hello World.'; 
sayHello = function () { //不建议采用这种方式来提供接口,看起来很不明显。 
alert(hello); 
} 
})(); 
sayHello();

可以改进为
(function (window) { 
var hello = 'Hello World.'; 
window.$ = { 
sayHello: function () { 
alert(hello); 
} 
}; 
})(window); 
$.sayHello(); //看起来像jQuery那么酷

var obj = (function () { 
var hello = 'Hello World.'; 
return { 
sayHello: function () { 
alert(hello); 
} 
}; 
})(); 
obj.sayHello();

陷阱二: 闭包的陷阱

(function () { //函数a 
var arr = []; 
  var i = 0; 
var j; 
for ( ; i < 3; i++) { 
arr.push(function () { //函数b 
alert(i * 10); 
}); 
} 
for (j in arr) { 
arr[j](); 
} 
})();

原以为函数数组arr里各个函数执行后,会弹出0,10,20,但是结果不是如此。结果是弹出30,30,30。
函数b访问的不是当时的 i的值, 而是直接访问变量i(用于都是取i最新的值)。
原因是函数b是函数a的内部函数,变量i对函数b是可见的,函数b每次都从i处获取最新的值。

这次改成:

(function () { //函数a 
var arr = []; 
var i = 0; 
  var j; 
for ( ; i < 3; i++) { 
arr.push((function (anotherI) { //函数m 
return function () { //函数b 
alert(anotherI * 10); 
} 
})(i)); // 此处为(function b(anotherI) {})(i) 
} 
for (j in arr) { 
arr[j](); 
} 
})();

这次执行后,终于弹出0,10,20。这是为什么呢。

函数b访问的是anotherI(当时的i的值),而不是直接访问变量i。
每次在arr.push前,都会定义一个新匿名的函数m。本例中定义了3个匿名函数m0,m1,m2,每当被调用后,他们的anotherI都得到当前i的值。每个m函数执行后都返回一个b函数。b0在m0里,b1在m1里,b2在m2里。b0只能访问m0的anotherI(为0),而b0访问不了m1的anotherI,因为m0和m1为不同的函数。

Javascript 相关文章推荐
判断页面是关闭还是刷新的js代码
Jan 28 Javascript
JavaScript类和继承 this属性使用说明
Sep 03 Javascript
boxy基于jquery的弹出层对话框插件扩展应用 弹出层选择器
Nov 21 Javascript
jquery实现图片裁剪思路及实现
Aug 16 Javascript
Jquery解析json字符串及json数组的方法
May 29 Javascript
每天一篇javascript学习小结(Boolean对象)
Nov 12 Javascript
学习JavaScript设计模式(封装)
Nov 26 Javascript
老司机带你解读jQuery插件开发流程
May 16 Javascript
浅谈Vue-cli 命令行工具分析
Nov 22 Javascript
解决webpack无法通过IP地址访问localhost的问题
Feb 22 Javascript
vue自定义树状结构图的实现方法
Oct 18 Javascript
浅谈vue.watch的触发条件是什么
Nov 07 Javascript
JavaScript.The.Good.Parts阅读笔记(一)假值与===运算符
Nov 16 #Javascript
javascript Array对象基础知识小结
Nov 16 #Javascript
纯js实现背景图片切换效果代码
Nov 14 #Javascript
基于jquery的自定义鼠标提示效果 jquery.toolTip
Nov 14 #Javascript
cnblogs中在闪存中屏蔽某人的实现代码
Nov 14 #Javascript
基于MooTools的很有创意的滚动条时钟动画
Nov 14 #Javascript
javascript 学习笔记(onchange等)
Nov 14 #Javascript
You might like
建立文件交换功能的脚本(二)
2006/10/09 PHP
PHP Class&amp;Object -- 解析PHP实现二叉树
2013/06/25 PHP
PHP和C#可共用的可逆加密算法详解
2015/10/26 PHP
PHP 范围解析操作符(::)用法分析【访问静态成员和类常量】
2020/04/14 PHP
javascript 继承实现方法
2009/08/26 Javascript
JS批量操作CSS属性详细解析
2013/12/16 Javascript
JavaScript实现找出数组中最长的连续数字序列
2014/09/03 Javascript
javascript实现微信分享
2014/12/23 Javascript
详解JavaScript中常用的函数类型
2015/11/18 Javascript
Bootstrap所支持的表单控件实例详解
2016/05/16 Javascript
JS制作类似选项卡切换的年历
2016/12/03 Javascript
清除浏览器缓存的几种方法总结(必看)
2016/12/09 Javascript
基于vue2.0实现的级联选择器
2017/06/09 Javascript
node.js + socket.io 实现点对点随机匹配聊天
2017/06/30 Javascript
Vue2(三)实现子菜单展开收缩,带动画效果实现方法
2019/04/28 Javascript
javascript实现移动端红包雨页面
2020/06/23 Javascript
[49:21]完美世界DOTA2联赛循环赛 Ink Ice vs LBZS BO2第二场 11.05
2020/11/06 DOTA
Python使用QRCode模块生成二维码实例详解
2017/06/14 Python
Numpy中矩阵matrix读取一列的方法及数组和矩阵的相互转换实例
2018/07/02 Python
Python使用微信itchat接口实现查看自己微信的信息功能详解
2019/08/22 Python
python boto和boto3操作bucket的示例
2020/10/30 Python
利用python如何实现猫捉老鼠小游戏
2020/12/04 Python
澳大利亚游乐场设备品牌:Lifespan Kids
2019/05/24 全球购物
VC++笔试题
2014/10/13 面试题
SQL Server 2000数据库的文件有哪些,分别进行描述
2013/03/30 面试题
面向对象设计的原则是什么
2013/02/13 面试题
优秀大学生的自我评价
2014/01/16 职场文书
法律进企业活动方案
2014/03/04 职场文书
领导班子奢靡之风查摆问题及整改措施
2014/09/27 职场文书
领导干部群众路线对照检查材料
2014/11/05 职场文书
2015年个人现实表现材料
2014/12/10 职场文书
幼儿园小班开学寄语
2015/05/27 职场文书
2016关于预防职务犯罪的心得体会
2016/01/21 职场文书
十大冰系宝可梦排名,颜值最高的阿罗拉九尾,第三使用率第一
2022/03/18 日漫
vue+iview实现手机号分段输入框
2022/03/25 Vue.js
利用Python实现翻译HTML中的文本字符串
2022/06/21 Python