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 相关文章推荐
表单项的name命名为submit、reset引起的问题
Dec 22 Javascript
javascript cookie解码函数(兼容ff)
Mar 17 Javascript
JS中confirm,alert,prompt函数区别分析
Jan 17 Javascript
Node.js 去掉种子(torrent)文件里的邪恶信息
Mar 27 Javascript
原生JavaScript实现瀑布流布局
Jun 28 Javascript
jQuery插件实现适用于移动端的地址选择器
Feb 18 Javascript
Vue.js中的图片引用路径的方式
Jul 28 Javascript
Node.js dgram模块实现UDP通信示例代码
Sep 26 Javascript
使用store来优化React组件的方法
Oct 23 Javascript
jQuery实现根据身份证号获取生日、年龄、性别等信息的方法
Jan 09 jQuery
原生js实现针对Dom节点的CRUD操作示例
Aug 26 Javascript
浅谈vue2的$refs在vue3组合式API中的替代方法
Apr 18 Vue.js
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检测图片木马多进制编程实践
2013/04/11 PHP
编写PHP脚本使WordPress的主题支持Widget侧边栏
2015/12/14 PHP
使用PHP下载CSS文件中的所有图片【几行代码即可实现】
2016/12/14 PHP
推荐自用 Javascript 缩图函数 (onDOMLoaded)……
2007/10/23 Javascript
JS中的public和private对象,即static修饰符
2012/01/18 Javascript
jQuery中 noConflict() 方法使用
2013/04/25 Javascript
jquery 字符串切割函数substring的用法说明
2014/02/11 Javascript
js判断url是否有效的两种方法
2014/03/04 Javascript
使用Javascript简单实现图片无缝滚动
2014/12/05 Javascript
JS上传图片前实现图片预览效果的方法
2015/03/02 Javascript
JQuery中$.each 和$(selector).each()的区别详解
2015/03/13 Javascript
JS实现可直接显示网页代码运行效果的HTML代码预览功能实例
2015/08/06 Javascript
AngularJS中的$watch(),$digest()和$apply()区分
2016/04/04 Javascript
Node.js connect ECONNREFUSED错误解决办法
2016/09/15 Javascript
jQuery实现的简单悬浮层功能完整实例
2017/01/23 Javascript
详解关于vue-area-linkage走过的坑
2018/06/27 Javascript
原生JS实现图片懒加载之页面性能优化
2019/04/26 Javascript
JS回调函数 callback的理解与使用案例分析
2019/09/09 Javascript
解决layui数据表格Date日期格式的回显Object的问题
2019/09/19 Javascript
微信小程序本地存储实现每日签到、连续签到功能
2019/10/09 Javascript
关于Vue中axios的封装实例详解
2019/10/20 Javascript
基于Element的组件改造的树形选择器(树形下拉框)
2020/02/27 Javascript
Node.js API详解之 string_decoder用法实例分析
2020/04/29 Javascript
js闭包和垃圾回收机制示例详解
2021/03/01 Javascript
[03:03]2014DOTA2西雅图国际邀请赛 Alliance战队巡礼
2014/07/07 DOTA
Mac OS X10.9安装的Python2.7升级Python3.3步骤详解
2013/12/04 Python
Python基于win32ui模块创建弹出式菜单示例
2018/05/09 Python
Python装饰器的执行过程实例分析
2018/06/04 Python
django Serializer序列化使用方法详解
2018/10/16 Python
Python Selenium 之数据驱动测试的实现
2019/08/01 Python
法制报告会主持词
2014/04/02 职场文书
师德师风演讲稿
2014/05/05 职场文书
《西门豹》教学反思
2016/02/23 职场文书
python cv2图像质量压缩的算法示例
2021/06/04 Python
python基于turtle绘制几何图形
2021/06/15 Python