Ajax In Action 附录B 3.5
来源:互联网 发布:c语言位运算符号 编辑:程序博客网 时间:2024/05/17 03:02
B3.5Closures in JavaScript
对于函数对象自己来讲,他还没有完成,为了引用它,我们需要传一个上下文对象和一系列的参数,有可能这些参数都是空的。最简单的,closure可以被看成是处理需要执行的资源的函数。
Closure是在JavaScript中隐式地创建的,不是显式。没有new Closure()这种构造函数,也没有办法可以控制一个closure对象。创建closure就像在代码块中声明一个函数一样简单,并让这个函数在声明块之外也能被访问。这个概念看起来有点奇怪,不过举个例子就很明白了。我们来定义一个简单的创建机器人的对象,并且能纪录机器人是什么时候被创建的。我们可以这么写:
function Robot(){
var createTime=new Date();
this.getAge=function(){
var now=new Date();
var age=now-createTime;
return age;
}
}
因为所有的机器人都是一样的,我们就没有必要通过构造函数来指定名字之类的东西。通常来说,我们把createTime作为一个属性,也就是:
this.createTime=new Date();
但是在这里我们故意把它作为一个局部变量,这个局部变量的作用域就是调用他的块的内部,也就是,我们的构造函数。在构造函数的第二行,我们定义了一个getAge()函数,这个函数是我们定义在另一个函数内部的,而且这个内部函数使用了createTime这个局部变量,本来createTime的作用域是外层的函数。这样,其实我们就完成了closure的创建。如果在页面装载的时候,定义一个机器人,并且问他多大了,
var robbie=new Robot();
window.onload=function(){
alert(robbie.getAge());
}
正常情况下,应该给我们返回一个10-50毫秒的值,差别就在脚本第一次执行和页面装载。虽然我们在构造函数作用域内把createTime定义成局部变量,但是只要机器人还在被引用,createTime占用的内存就不会被回收,因为他还属于一个closure。
只有在内部函数在外层函数的定义体内创建的时候才有用,如果我们重新写getAge()函数,像这样:
function Robot(){
var createTime=new Date();
this.getAge=roboAge;
}
function roboAge(){
var now=new Date();
var age=now-createTime;
return age;
};
这样closure就不会被创建,而且会得到一个createTime没有定义的错误。
Closure很容易被创建,而且是太容易被创建了,因为它总是将一些局部变量绑定,阻止垃圾回收机制回收它们。如果DOM的结点,通过这种方式创建,将会导致内存溢出。
创建closure的最普遍的情况就是在绑定事件处理器到事件的时候,像我们在B3.4提到过的一样,被上下文应用的回调函数往往不是很好用。我们为多余的引用定义一些模式,允许我们从DOM元素来检索模型。Closure为我们提供了可选择的方法,如下:
myObj.prototype.createView=function(){
...
this.titleBar=document.createElement("div");
var modelObj=this;
this.titleBar.onclick=function(){
fooEventHandler.call(modelObj);
}
}
我们定义的匿名的onclick处理器函数引用了局部变量modelObj,所以一个closure就被创建了,函数被引用的时候,modelObj也就可用了。注意closure只负责局部变量,而不是那些通过this关键字引用的变量。
我们在第二章的时候在ContentLoder对象用到了这种方法,因为IE浏览器提供的onreadystatechange回调将窗口作为函数的上下文返回。因为window是全局对象,我们就没有办法知道哪个ContentLoader的readySatate改变了,除非我们通过closure给相关的装载对象传递一个引用。
我推荐普通得Ajax程序员尽量避免closure,如果你使用原型来给你自定义的类型定义函数,那么你没有复制函数,也没有创建closure。让我们根据这个建议来重写一下Robot类:
function Robot(){
this.createTime=new Date();
}
Robot.prototype.getAge=function(){
var now=new Date();
var age=now-this.createTime;
return age;
};
getAge()函数只定义了一次,因为它是定义在原型上的,在每创建一个Robot的时候都是可以访问的。
Closure有他们的用处,但是我们得把他们看成高级课题,如果你想进一步学习closure,那么资源部分的Jim Ley的文章,作为一个入门还是不错的。
- Ajax In Action 附录B 3.5
- Ajax In Action 附录B B1
- Ajax In Action 附录B 2.2
- Ajax In Action 附录B 2.6
- Ajax In Action 附录B 3.1
- Ajax In Action 附录 B 3.4
- Ajax In Action 附录 B2.1
- Ajax In Action 附录 B2.3
- Ajax In Action 附录 B2.4
- Ajax In Action 附录 B2.5
- Ajax In Action 附录 B3.2
- Ajax In Action 附录 B3.3
- 面向对象程序员JavaScript指南---摘自《Ajax in action》附录B
- AJAX in Action
- ajax in action (序言)
- Ajax in action读书笔记
- AJAX in Action
- AJAX in Action
- boost源码剖析之:泛型函数指针类boost::function(rev#3)
- boost源码剖析之:Tuple Types(rev#2)
- boost源码剖析之:泛型多维数组类multi_array
- O Architecture! My Architecture!
- Little Miss Sunshine - The most moving movie of 2006
- Ajax In Action 附录B 3.5
- Beautiful Proof - Data-Race-Free Implies Sequential Consistency铪铪
- 《Working Effectively With Legacy Code》译序
- Intuition out of counter-intuition
- 管理观点系列:团队管理
- C++0x简讯
- 关于C++0x内存模型和序列点的一些思考
- How Does it End()?
- .net面试题9