作用域解析和闭包
ricoyu
2010-05-15
作用域解析和闭包
window.addEventListener('load', initAnchors, false);
function registerListener(anchor, i){ function initAnchors(){ |
|
s海若
2010-05-30
老生常谈。不过不知道你是怎么得出这个结论的:
引用 每次调用registerListener 函数都会生成一个该函数的一个副本,以维护正确的变量作用域. 据我所知函数的作用域链是他定义时确定的,调用时只是在作用域链最前端加了个调用对象,并用arguments初始化。 这应该是一个参数传递的问题,比如做如下修改: function registerListener(anchor,iObj){ anchor.addEventListener('click', function(){ alert('My id is anchor'+iObj.i); }, false); } function initAnchors(e){ for(var i=0,iObj={};i<=3;i++){ iObj.i=i; var anchor = document.getElementById('anchor'+i); registerListener(anchor, iObj); } } registerListener中的iObj还是同一个Object,所以结果和在initAnchors里定义一样。 因为javascript调用函数的时候是传值的,i是原始类型,所以每次调用registerListener都把i当前的值传过去了,自然每次alert出来的形参i都不是同一个i. |
|
ricoyu
2010-05-31
小伙子言辞很犀利。 不过有一点,你的代码根本就不能正常工作。
下面是我用你的代码在FF中的demo,你有兴趣的话将下面的代码保存为一个HTML文件然后在你的浏览器中测试,不过IE版本的demo我没有提供哦~ 自己写一个测试一下吧! <html> <head> <script language="javascript"> function registerListener(anchor,iObj){ anchor.addEventListener('click', function(){ alert('My id is anchor'+iObj.i); }, false); } function initAnchors(e){ for(var i=0,iObj={};i<=3;i++){ iObj.i=i; var anchor = document.getElementById('anchor'+i); registerListener(anchor, iObj); } } window.addEventListener('load', initAnchors, false); </script> </head> <body> <a href="#" id='anchor0'>a1</a> <a href="#" id='anchor1'>a2</a> <a href="#" id='anchor2'>a3</a> <a href="#" id='anchor3'>a4</a> </body> </html> |
|
ricoyu
2010-05-31
另外,你可能对for循环没有很好的理解。下面我稍微改动一下你的代码,你再测试一下结果又什么不同。
<html> <head> <script language="javascript"> function registerListener(anchor,iObj){ anchor.addEventListener('click', function(){ alert('My id is anchor'+iObj.i); }, false); } function initAnchors(e){ for(var i=0;i<=3;i++){ var iObj = {}; iObj.i=i; var anchor = document.getElementById('anchor'+i); registerListener(anchor, iObj); } } window.addEventListener('load', initAnchors, false); </script> </head> <body> <a href="#" id='anchor0'>a1</a> <a href="#" id='anchor1'>a2</a> <a href="#" id='anchor2'>a3</a> <a href="#" id='anchor3'>a4</a> </body> </html> 我理解你要表达的意思,从你的代码中我看出你有Java等面向对象编程经验,但是可以肯定的是对于JavaScript,你没有一个很好的理解。 然后,你再对比一下经我改动过后的你的有问题的代码和我之前提供的匿名函数版本的那段代码,哪一个更加优雅。 |
|
mixmaster
2010-06-08
“函数的一个副本”这个提法确实很模糊,不够准确。
更准确的说法应该是:每次函数被调用时,系统都会创建一个context(上下文)对象,用于存储参数和局部变量。在函数结束时,这个context对象通常会被自动销毁。如果函数内创建了闭包,使得context中某些数据在函数结束后依然被引用,系统会保留context对象,延长其生命期,以使引用持续有效。 我相信你说的“副本”就是指context对象,只是context对象不是函数开始被调用时对当前上下文环境的拷贝,而是系统视情况在函数结束时对当前上下文环境的保留。发生的时间点和实现手段不一样。 |
|
ricoyu
2010-06-10
确实是你说的这个意思,我没有表达好。我觉得这篇东西有助于大家对闭包的理解,所以发来跟大家分享。
引用 只是context对象不是函数开始被调用时对当前上下文环境的拷贝,而是系统视情况在函数结束时对当前上下文环境的保留 你的这段话非常精辟,抓住了关键点! |
|
select*from爱
2010-06-28
犀利哥,你抽的是什么牌子的烟?
|
|
ricoyu
2010-06-30
以前一般抽中华,不过现在戒了
|
|
lvhjean
2010-07-21
学习了。
引用 只是context对象不是函数开始被调用时对当前上下文环境的拷贝,而是系统视情况在函数结束时对当前上下文环境的保留 这个地方有关上下文的描述,的确给自己上了一课。 |
|
hyj1254
2010-07-21
每次函数被调用时,系统都会创建一个context(上下文)对象,用于存储参数和局部变量。在函数结束时,这个context对象通常会被自动销毁。如果函数内创建了闭包,使得context中某些数据在函数结束后依然被引用,系统会保留context对象,延长其生命期,以使引用持续有效 精辟,说出了我想说却不能准确地说的话。 |