javaScript高级教程(二)Scope Chain & Closure Example
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset=gb2312 /> 5 <title>js</title> 6 <script> 7 //function语句在解析时会被提升,不管function语句放置在哪里, 8 //它都会被移动到所在作用域的顶层。 9 addEvent(window,'load',initAnchors); 10 11 12 function initAnchors(){ 13 for(var i=1; i<=3; i++){ 14 var anchor = $('anchor'+i); 15 registerListener(anchor,i); //函数中函数,也就是闭包,registerListener可以保存外部变量的值。 16 } 17 }; 18 /* 19 把事件处理函数注册到一个独立的函数中。 20 21 现在click事件处理函数的外部作用域变成了registerListener()函数。 22 23 每次调用registerListener()函数时都会生成该函数的一个副本, 24 以维护正确的变量作用域。 25 */ 26 function registerListener(anchor,i){ 27 addEvent(anchor,'click',function(){ 28 alert('my id is anchor'+i); 29 }); 30 } 31 /* 32 因为i的值实际上是单击事件发生时才从作用域链中取得。 33 当单击事件必发生时,initAnchors()已经执行完毕(验证:在循环加入alert(i)后,打开网页会弹出三次框)。 34 此时i=4。所以alert会显示相同信息。 35 36 具体来说,当click事件处理函数被调用时,它会先在事件处理函数的内部作用域中查找i的值, 37 但click事件的匿名处理函数中没有定义i的值,所以它再到其外部作用域(initAnchors()函数)中查找。 38 而外部作用域中i=4。 39 40 function initAnchors(){ 41 for(var i=1; i<=3; i++){ 42 //alert(i); 43 var anchor = $('anchor'+i); 44 addEvent(anchor,'click',function(){ 45 alert('my id is anchor'+i); 46 }); 47 } 48 }; 49 50 */ 51 function addEvent( node, type, listener ) { 52 if (node.addEventListener) { 53 // W3C method 54 node.addEventListener( type, listener, false ); 55 return true; 56 } else if(node.attachEvent) { 57 // MSIE method 58 //使用attachEvent()注册的回调函数没有Event参数,需要读取Window对象的event属性 59 //使用attachEvent()作为全局函数调用。而不是事件发生其上的文档元素的方法来调用 60 //也就是说attachEvent()注册的回调函数执行时,this指向window对象,而不是事件目标元素。 61 //下面修正这些问题 62 node['e'+type+listener] = listener; 63 node[type+listener] = function(){ 64 node['e'+type+listener]( window.event ); 65 } 66 67 //IE事件模型不支持事件捕获,所以需要两个参数 68 node.attachEvent( 'on'+type, node[type+listener] ); 69 70 71 return true; 72 } 73 74 // Didn't have either so return false 75 return false; 76 }; 77 78 function $() { 79 var elements = new Array(); 80 81 // Find all the elements supplied as arguments 82 for (var i = 0; i < arguments.length; i++) { 83 var element = arguments[i]; 84 85 // If the argument is a string assume it's an id 86 if (typeof element == 'string') { 87 element = document.getElementById(element); 88 } 89 90 // If only one argument was supplied, return the element immediately 91 if (arguments.length == 1) { 92 return element; 93 } 94 95 // Otherwise add it to the array 96 elements.push(element); 97 } 98 99 // Return the array of multiple requested elements 100 return elements; 101 }; 102 </script> 103 </head> 104 105 <body> 106 <ul> 107 <li><a href="#" id="anchor1">Anchor 1</a></li> 108 <li><a href="#" id="anchor2">Anchor 2</a></li> 109 <li><a href="#" id="anchor3">Anchor 3</a></li> 110 </ul> 111 112 </body> 113 </html>