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 相关文章推荐
解决Jquery load()加载GB2312页面时出现乱码的两种方案
Sep 10 Javascript
js实现基于正则表达式的轻量提示插件
Aug 29 Javascript
jquery+CSS3实现淘宝移动网页菜单效果
Aug 31 Javascript
如何解决ligerUI布局时Center中的Tab高度大小
Nov 24 Javascript
jQuery基于json与cookie实现购物车的方法
Apr 15 Javascript
AngularJS 简单应用实例
Jul 28 Javascript
AngularJS定时器的使用与移除操作方法【interval与timeout】
Dec 14 Javascript
JS中使用正则表达式g模式和非g模式的区别
Apr 01 Javascript
AngularJS 限定$scope的范围实例详解
Jun 23 Javascript
js 客户端打印html 并且去掉页眉、页脚的实例
Nov 03 Javascript
Layui表格行工具事件与数据回填方法
Sep 13 Javascript
JavaScript实现多球运动效果
Sep 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
PHP生成不同颜色、不同大小的tag标签函数
2013/09/23 PHP
php图像处理函数imagecopyresampled用法详解
2016/12/02 PHP
extjs tabpanel限制选项卡数量实现思路及代码
2013/04/02 Javascript
jquery数组之存放checkbox全选值示例代码
2013/12/20 Javascript
关闭浏览器窗口弹出提示框并且可以控制其失效
2014/04/15 Javascript
简单对比分析JavaScript中的apply,call与this的使用
2015/12/04 Javascript
laypage分页控件使用实例详解
2016/05/19 Javascript
vue在使用ECharts时的异步更新和数据加载详解
2017/11/22 Javascript
详解Vue快速零配置的打包工具——parcel
2018/01/16 Javascript
微信小程序实现动态显示和隐藏某个控件功能示例
2018/12/14 Javascript
Vue2.x Todo之自定义指令实现自动聚焦的方法
2019/01/08 Javascript
this.$toast() 了解一下?
2019/04/18 Javascript
Vue.js轮播图走马灯代码实例(全)
2019/05/08 Javascript
JavaScript面向对象编程小游戏---贪吃蛇代码实例
2019/05/15 Javascript
Vue监听页面刷新和关闭功能
2019/06/20 Javascript
[15:28]DOTA2 HEROS教学视频教你分分钟做大人-剧毒术士
2014/06/13 DOTA
[46:38]完美世界DOTA2联赛PWL S2 Magma vs PXG 第三场 11.28
2020/12/02 DOTA
一个计算身份证号码校验位的Python小程序
2014/08/15 Python
Python常用随机数与随机字符串方法实例
2015/04/09 Python
Python简单实现查找一个字符串中最长不重复子串的方法
2018/03/26 Python
python pandas.DataFrame选取、修改数据最好用.loc,.iloc,.ix实现
2018/06/11 Python
Python小工具之消耗系统指定大小内存的方法
2018/12/03 Python
python write无法写入文件的解决方法
2019/01/23 Python
python制作英语翻译小工具代码实例
2019/09/09 Python
Python实现链表反转的方法分析【迭代法与递归法】
2020/02/22 Python
Ubuntu中配置TensorFlow使用环境的方法
2020/04/21 Python
css3实现input输入框颜色渐变发光效果代码
2014/04/02 HTML / CSS
html5 video标签屏蔽右键视频另存为的js代码
2013/11/12 HTML / CSS
iPad和Surface Pro蓝牙键盘:Brydge
2018/11/10 全球购物
如何在Shell脚本中使用函数
2015/09/06 面试题
普通大学毕业生自荐信
2013/11/04 职场文书
2014审计局领导班子民主生活会对照检查材料思想汇报
2014/09/20 职场文书
想创业成功,需要掌握这些要点
2019/12/06 职场文书
解决Pytorch半精度浮点型网络训练的问题
2021/05/24 Python
Java 写一个简单的图书管理系统
2022/04/26 Java/Android
MySQL选择合适的备份策略和备份工具
2022/06/01 MySQL