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 相关文章推荐
如何在Mozilla Gecko 用Javascript加载XSL
Jan 09 Javascript
用javascript判断IE版本号简单实用且向后兼容
Sep 11 Javascript
使用jQuery实现图片遮罩半透明坠落遮挡
Mar 16 Javascript
学习JavaScript设计模式(链式调用)
Nov 26 Javascript
浅谈javascript运算符——条件,逗号,赋值,()和void运算符
Jul 15 Javascript
jQuery视差滚动效果网页实现方法经验总结
Sep 29 Javascript
Vue 固定头 固定列 点击表头可排序的表格组件
Nov 25 Javascript
详解Vue.js入门环境搭建
Mar 17 Javascript
vue.js实例todoList项目
Jul 07 Javascript
关于js中的鼠标事件总结
Jul 11 Javascript
Easy UI动态树点击文字实现展开关闭功能
Sep 30 Javascript
bootstrap-paginator服务器端分页使用方法详解
Feb 13 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
古巴咖啡 Cubita琥爵咖啡 独特的加勒比海风味咖啡
2021/03/06 新手入门
PHP SPL标准库中的常用函数介绍
2015/05/11 PHP
PHP _construct()函数讲解
2019/02/03 PHP
Thinkphp5+plupload实现的图片上传功能示例【支持实时预览】
2019/05/08 PHP
JavaScript 模仿vbs中的 DateAdd() 函数的代码
2007/08/13 Javascript
JavaScript 拾漏补遗
2009/12/27 Javascript
JavaScript调用Activex控件的事件的实现方法
2010/04/11 Javascript
关于jQuery object and DOM element
2013/04/15 Javascript
千分位数字格式化(用逗号隔开 代码已做了修改 支持0-9位逗号隔开)的JS代码
2013/12/05 Javascript
js实现倒计时时钟的示例代码
2013/12/17 Javascript
javascript 中that的含义示例介绍
2014/05/14 Javascript
jQuery控制TR显示隐藏的几种方法
2014/06/18 Javascript
chrome不支持form.submit的解决方案
2015/04/28 Javascript
jQuery EasyUI编辑DataGrid用combobox实现多级联动
2016/08/29 Javascript
JS在浏览器中解析Base64编码图像
2017/02/09 Javascript
Vue.js实战之利用vue-router实现跳转页面
2017/04/01 Javascript
jquery实现图片放大点击切换
2017/06/06 jQuery
Node.js五大应用性能技巧小结(必须收藏)
2017/08/09 Javascript
详解vue 实例方法和数据
2017/10/23 Javascript
vue 组件中slot插口的具体用法
2018/04/03 Javascript
Bootstrap table中toolbar新增条件查询及refresh参数使用方法
2018/05/18 Javascript
微信小程序点击顶部导航栏切换样式代码实例
2019/11/12 Javascript
VUE前端从后台请求过来的数据进行转换数据结构操作
2020/11/11 Javascript
[01:02:38]DOTA2-DPC中国联赛定级赛 LBZS vs Phoenix BO3第二场 1月10日
2021/03/11 DOTA
python optparse模块使用实例
2015/04/09 Python
python字典get()方法用法分析
2015/04/17 Python
Python映射拆分操作符用法实例
2015/05/19 Python
PyTorch中 tensor.detach() 和 tensor.data 的区别详解
2020/01/06 Python
python pandas移动窗口函数rolling的用法
2020/02/29 Python
css3选择器基本介绍
2014/12/15 HTML / CSS
mysql的最长数据库名,表名,字段名可以是多长
2014/04/21 面试题
六个一活动实施方案
2014/03/21 职场文书
毕业典礼主持词大全
2014/03/26 职场文书
十大最强火系宝可梦,喷火龙上榜,第一名有双火属性
2022/03/18 日漫
MySQL中一条SQL查询语句是如何执行的
2022/04/08 MySQL
Docker下安装Oracle19c
2022/04/13 Servers