这段时间在javascript版块学习了很多,其中感触最深的就是对js继承和对变量的隐藏上。
我们都知道全局变量的危险性以及可能的与其他库或者js文件冲突问题,所以很多时候我们都在想办法去隐藏我们的全局变量,最简单的方法莫过于加入“命名空间”
- JScript code
var Lib = {}; Lib.Do = {}; ...
把所有的内容都放到一个Lib里面。这样我们就可以不用为全局变量的污染而担忧了。
当然,说到js,就不得不提那强大的闭包,在这里我们也可以通过闭包来解决全局变量的污染。比如我们希望构造一个person对象,其对象中有name、age、sex3个属性。那么我们通常的做法是什么呢?
- JScript code
function Person(name,age,sex) { this.name = name || "jee"; this.age = age || 24; this.sex = sex || true }
这种模仿类的方法使从类对象语言如(C#、java、C++)等专业的童鞋来说非常的容易接受,我们可以加上属性的getter和setter
Person.prototype.getName = function() {
return this.name;
};
Person.prototype.setName = function(name) {
if (name) {
this.name = name;
}
}
现在我们理所当然的可以去创建一个对象
- JScript code
var p = new Person("jee",24,true); alert(p.getName());
然而,我们同样可以这样去获取name
- JScript code
alert(p.name);
这很糟糕,因为他暴露了我们的属性。通过闭包我们可以去解决这个问题,因为在js中,函数是可以被当作返回值返回的。
- JScript code
function person(name,age,sex) { var _name = name || "jee"; var _age = age || 24; var _sex = sex || true; return { getname : function() { return _name; }, setname : function(n) { _name = n; } getage : function() { return _age } ... }; }
var p = person("jee",24,true);
这个时候你只能通过getname,setname...等方法来进行属性的存取了。
在这里我遇到过这样一个问题,在使用闭包时,内部的函数使用的是外包函数的实际变量而非copy。我们看这样的代码
- HTML code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <script type="text/javascript"> window.onload = function() { var li = document.getElementsByTagName("li"); for (var i = 0; i < li.length; i++) { li[i].onclick = function() { alert(i); }; } }; </script> <style> li { width:100px; background-color:red; cursor:pointer; line-height:20px; margin-bottom:5px; } </style> </head> <body> <ul> <li></li> <li></li> <li></li> </ul> </body> </html>
点击每个li看看发生了什么,对,都是3.因为这是函数构造的时候绑定了i,而非是单纯的得到了i在绑定时的值。这个教训让 我深刻的认识到了这个问题。也在私下找了一些相关资料,现在我们可以把js段代码修改如下
- JScript code
window.onload = function() { var li = document.getElementsByTagName("li"); for (var i = 0; i < li.length; i++) { li[i].onclick = function(i) { return function() { alert(i); }; }(i);//i作为参数传递给这个自执行函数,在绑定onclick的时候,该函数已执行,而这个函数体内部调用的就是该i的值了 } };
在运行看看,好了,可以得到我们想要的结果了,这里勘误一下《javascript语言精粹》里第39页类似例子多了个e,大家把返回函数的参数e去掉就可以正确运行了。
因为这样修改后,onclick绑定的是一个自执行函数返回的一个函数,而这个函数绑定的是作为参数传递进来的i的值。