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

所属分类: 网络编程 / JavaScript 阅读数: 326
收藏 0 赞 0 分享
如代码块
复制代码 代码如下:

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为不同的函数。
更多精彩内容其他人还在看

jQuery LigerUI 使用教程表格篇(1)

ligerGrid是ligerui系列插件的核心控件,用户可以快速地创建一个美观,而且功能强大的表格,支持排序、分页、多表头、固定列等等
收藏 0 赞 0 分享

JavaScript中常用的运算符小结

JavaScript中常用的运算符小结,需要的朋友可以参考下。
收藏 0 赞 0 分享

深入理解JavaScript系列(13) This? Yes,this!

在这篇文章里,我们将讨论跟执行上下文直接相关的更多细节。讨论的主题就是this关键字。实践证明,这个主题很难,在不同执行上下文中this的确定经常会发生问题
收藏 0 赞 0 分享

javascript (用setTimeout而非setInterval)

javascript (用setTimeout而非setInterval)如果用setInterval 可能出现 下次调用会在前一次调用前调用
收藏 0 赞 0 分享

JavaScript中两个感叹号的作用说明

用两个感叹号的作用就在于,如果明确设置了o中flag的值(非null/undefined/0""/等值),自然test就会取跟o.flag一样的值;如果没有设置,test就会默认为false,而不是null或undefined
收藏 0 赞 0 分享

javascript写的简单的计算器,内容很多,方法实用,推荐

最近用javascript写了一个简单的计算器,自己测试感觉还好,代码都给了注释,非常不错,推荐大家学习。
收藏 0 赞 0 分享

js的表单操作 简单计算器

javascript写的简单的加减乘除计算器,里面涉及到一些方法还是很实用的哦,新手不要错过
收藏 0 赞 0 分享

Jquery中删除元素的实现代码

empty用来删除指定元素的子元素,remove用来删除元素,或者设定细化条件执行删除
收藏 0 赞 0 分享

javaScript 利用闭包模拟对象的私有属性

JavaScript缺少块级作用域,没有private修饰符,但它具有函数作用域。作用域的好处是内部函数可以访问它们的外部函数的参数和变量(除了this和argument
收藏 0 赞 0 分享

为JavaScript类型增加方法的实现代码(增加功能)

大家在js开发过程中有些功能已经满足不了我们的需求,或没有我们需要的功能,那么我们就可以自己扩展下,个性化js
收藏 0 赞 0 分享
查看更多