Javascript闭包(回调函数)的问题
回调函数网络上一大堆,这里举个实际的例子:
<script src="../javascripts/jquery-1.4.2.js"></script> <script language="javascript"> $(document).ready(init); function init(){ console.log("....init"); var sd = new Date(); $('.list').each( function(){ this.onclick= function(){ console.log("you click,haha"); process(sd); }; }); }; function process(youDate){ console.log("I got it:" + youDate); } </script> <div id="nav"> <div>11</div> <div>22</div> <div>33</div> </div>
逻辑很简单:当页面加载时注册回调函数,当点击div时激发回调函数。这里注册和激发是异步的。
注意回调函数可以访问上一级的成员变量sd(或许在FP中称为运行上下文),这个跟java的observer模式中的内部类可以访问容器类的this指针一样,这就是说当你点击div时,原来已经产生的时间变量sd还在,这样打印出来的时间都是旧的时间。这是closure的灵活强大的地方(《JavaScript: The Good Parts》里面说,“使用闭包来进行信息掩藏的方式,它是另一个减少有效全局污染的方法”。真知灼见啊!,否则又要使用大量的全局变量),但是跟Java一样,这里由于引用的关系可能会出现垃圾回收的困难,java用弱引用来处理这个问题。这篇文章Memory leak patterns in JavaScript有描述,里面提到了circular references,大概意思是javascript对象引用了DOM对象,而DOM对象反过来又引用了javascript对象。上面代码改成:
$('.list').click( function(){ console.log("you click,haha"); process(s); });
可能更好点,因为this.onclick处可能隐含了DOM对象到Javascript对象的引用,而在$(‘.list’)处又有javascript obj到dom obj的引用。这个我没有求证,毕竟这种内存泄漏在浏览器上关掉当前页后就应该不存在了,不会引起很明显的问题,知道有这个事就好了。