其实这个你就直接分析代码就 行了
(function() { 
        var el = document.getElementById('el'); 
        el.onclick = clickHandler; 
    })(); 
//(function(){})()这就是让函数直接调用
//然后直接将clickHandler函数绑定到el的onclick句柄上
//所以e1点击 就执行clickHandler函数
var clickHandler = function() { 
        this.style.backgroundColor = 'red'; 
    } 

解决方案 »

  1.   

    //我主要是不明白:跟有引用循环的这段代码的区别?
    function addHandler() {
        var el = document.getElementById('el');
        el.onclick = function() {
            this.style.backgroundColor = 'red';
        }
    }//无引用循环
    function addHandler() { 
        var clickHandler = function() { 
            this.style.backgroundColor = 'red'; 
        } 
        (function() { 
            var el = document.getElementById('el'); 
            el.onclick = clickHandler; 
        })(); 
    } //这难道不是间接引用循环吗?
      

  2.   

    js core el 引用 DOM 的一个元素DOM 的一个元素的onclick 引用 clickHandlerclickHandler 引用 匿名function()匿名function() 引用 this //而this就是 DOM 的一个元素
      

  3.   

    (function() { 
            var el = document.getElementById('el'); 
            el.onclick = clickHandler; 
        })(); 
    他引用了谁?就像alert
      

  4.   

    很不错^^假如说
    attachEvent也会产生循环引用的话。。
    那么通常可以用event.target
    来确定event

    addEventListener会很好的bind.this不会漂移到window那里。
      

  5.   

    如果直接:function addHandler() {
        document.getElementById('el').onclick = function() {
            this.style.backgroundColor = 'red';
        }
    }會不會形成循環引用呢? ^_^
      

  6.   

    最佳的addEvent是怎样诞生的[摘自网络]2007-08-24 12:44 
    IE的 JScript 存在内存泄露的bug 想必大家都清楚或者有耳闻了。这是由于IE的内存回收管理器的一个设计错误导致的。当我们编写脚本的时候创建了交叉引用,例如如下代码: window.onload = function () {  
         var x = document.getElementsByTagName(’H3’);  
         for (var i=0;i<x.length;i++)  
         {  
             x[i].onclick = openClose;  
             x[i].relatedElement = x[i].nextSibling; // simplified situation  
             x[i].relatedElement.relatedElement = x[i];  
         }  
    }或者在函数中使用脚本语言最常见的闭句Closures的时候,IE都无法回收内存。而闭句在给DOM对象注册事件处理器(event handler)的时候最为常用。Novemberborn提供了一些example可以让你运行并切实感受到这个bug。  
    我最喜爱的QuirkMode 去年初意识到这个bug存在巨大隐患,觉得有必要呼吁广大web开发者关注并竭力避免这个问题,于是举办了一个慈善邀请赛,鼓励大家提交各自addEvent/removeEvent 方案。并终于在去年10月下旬宣布了他们认为的胜利者:John Resig,让John赢得胜利的代码如下:   function addEvent( obj, type, fn ) {  
       if ( obj.attachEvent ) {  
         obj[’e’+type+fn] = fn;  
         obj[type+fn] = function(){obj[’e’+type+fn]( window.event );}  
         obj.attachEvent( ’on’+type, obj[type+fn] );  
       } else  
         obj.addEventListener( type, fn, false );  
    }  
    function removeEvent( obj, type, fn ) {  
       if ( obj.detachEvent ) {  
         obj.detachEvent( ’on’+type, obj[type+fn] );  
         obj[type+fn] = null;  
       } else  
         obj.removeEventListener( type, fn, false );  
    }  
    QuirkMode 对选择John为胜利者的解释概括来说就是以上代码最简洁有效,在避免内存问题的同时还巧妙的保证了this关键字在ie的attachEvent中能正常工作。缺点当然还是存在:   不支持 Netscape 4 和 Explorer 5 Mac。(有可能国内的程序员会嗤之以鼻,但国外很强调广泛的兼容性)   
    在 removeEvent 中遗漏了remove obj["e"+type+fn]。   
    总之不管怎么说,简单取胜。  
    结果一出,众多参赛与评论者不服气,很快又挑出了John的代码的几处毛病:   addEvent中本身就使用了闭句,所以没有根本解决IE内存泄露的问题。   
    没有解决同类型的事件可能被重复注册而被IE重复执行的问题。   
    几个高手于是提出了改进性的方案: /*  
    Original idea by John Resig  
    Tweaked by Scott Andrew LePera, Dean Edwards and Peter-Paul Koch  
    Fixed for IE by Tino Zijdel (crisp)  
         Note that in IE this will cause memory leaks and still doesn’t quite function the same as in browsers that do support the W3C event model:  
         - event execution order is not the same (LIFO in IE against FIFO)  
         - functions attached to the same event on the same element multiple times will also get executed multiple times in IE  
    */  
    function addEvent( obj, type, fn ) {  
         if (obj.addEventListener)  
             obj.addEventListener( type, fn, false );  
         else if (obj.attachEvent) {  
             obj["e"+type+fn] = fn;  
             obj.attachEvent( "on"+type, function() { obj["e"+type+fn](); } );  
         }  
    }  
    function removeEvent( obj, type, fn ) {  
         if (obj.removeEventListener)  
             obj.removeEventListener( type, fn, false );  
         else if (obj.detachEvent) {  
             obj.detachEvent( "on"+type, obj["e"+type+fn] );  
             obj["e"+type+fn] = null;  
         }  
    }  
    很明显,虽然修正了John代码的一些不足。但内存泄露依然存在,部分浏览器依然不支持,还是无法避免ie重复注册。另外根据注释:当在同一个对象上注册多个事件处理器的时候,IE与其他浏览器的执行顺序是不同的,这又是一个隐患。  几天之后,一个被认为最严谨的方案由Dean Edwards 提出。Dean他的方案与众不同:   不执行对象检测(Object detection)   
    没有调用 addeventListener/attachEvent 方法   
    保持this关键字的运行于正确的上下文环境   
    正确传递 event 对象参数   
    完全跨浏览器至此(包括IE4和NS4)   
    不存在内存泄露   
    Dean的代码如下: // written by Dean Edwards, 2005  
    // http://dean.edwards.name/function ;addEvent(element, type, handler) {  
         // assign each event handler a unique ID  
         // 为事件处理函数设定一个唯一值  
         if (!handler.$$guid) handler.$$guid = addEvent.guid++;  
         // create a hash table of event types for the element  
         if (!element.events) element.events = {};  
         // create a hash table of event handlers for each element/event pair  
         var handlers = element.events[type];  
         if (!handlers) {  
             handlers = element.events[type] = {};  
             // store the existing event handler (if there is one)  
             // 如果对象已经注册有事件处理,那么要保留下来,并保存为第一个  
             if (element["on" + type]) {  
                 handlers[0] = element["on" + type];  
             }  
         }  
         // store the event handler in the hash table  
         handlers[handler.$$guid] = handler;  
         // assign a global event handler to do all the work  
         // 指派一个全局函数做统一的事件处理,同时避免了反复注册  
         element["on" + type] = handleEvent;  
    };  
    // a counter used to create unique IDs  
    addEvent.guid = 1;function removeEvent(element, type, handler) {  
         // delete the event handler from the hash table  
         if (element.events && element.events[type]) {  
             delete element.events[type][handler.$$guid];  
         }  
    };function handleEvent(event) {  
         // grab the event object (IE uses a global event object)  
         event = event || window.event;  
         // get a reference to the hash table of event handlers  
         // 这里的 this 随 handlerEvent function 被触发的source element 变化而变化  
         var handlers = this.events[event.type];  
         // execute each event handler  
         for (var i in handlers) {  
             //这样写才能保证注册的事件处理函数中的 this 得到正确的引用,直接handlers[i]()是不行的          
             this.$$handleEvent = handlers[i];  
             this.$$handleEvent(event);  
         }  
    };  
    这段代码相比之前就大了不少了,不过确实很精妙。可是这段代码却引入了其他的问题,比如无法处理事件处理函数的返回值,for..in循环可能因为(Object.prototype)的错误应用而中断等等...很快Dean推出一个"updated version"。  要做到最好真的好辛苦。  目前似乎Dean的最终版本是最全面的解决方案。不过就我个人意见,感觉有些吹毛求疵了。尽量使用浏览器本身的实现和保持简单是我一贯坚持的主张。但洋人这种严谨的态度,还是让我深深敬佩。 ******************************************************************如果打断被闭包引入的循环引用的窍门是添加另外一个闭包,Dean 一定会使用的对吧?
      

  7.   

        obj[’e’+type+fn] = fn;  
        obj[type+fn] = function(){obj[’e’+type+fn]( window.event );}  
        obj.attachEvent( ’on’+type, obj[type+fn] );  这样写很明显有内存泄露 - -
      

  8.   

    循环的很明显object.[type+fn].[[scope]].obj
    就是object这里一般用window.event.srcElement,就可以。不过问题是写drag时onmousemove会导致srcElement非期待值,这很郁闷所以这里的循环,偶一般都忽略。。
      

  9.   

    。。
    我测过,IE已经fixed了某些memory leak的bug.现在以循环引用来确定是否有leak是错误的~
      

  10.   


    addEvent
    if (typeof addEvent != 'function')
    {
     var addEvent = function(o, t, f, l)
     {
      var d = 'addEventListener', n = 'on' + t, rO = o, rT = t, rF = f, rL = l;
      if (o[d] && !l) return o[d](t, f, false);
      if (!o._evts) o._evts = {};
      if (!o._evts[t])
      {
       o._evts[t] = o[n] ? { b: o[n] } : {};
       o[n] = new Function('e',
        'var r = true, o = this, a = o._evts["' + t + '"], i; for (i in a) {' +
         'o._f = a[i]; r = o._f(e||window.event) != false && r; o._f = null;' +
         '} return r');
       if (t != 'unload') addEvent(window, 'unload', function() {
        removeEvent(rO, rT, rF, rL);
       });
      }
      if (!f._i) f._i = addEvent._i++;
      o._evts[t][f._i] = f;
     };
     addEvent._i = 1;
     var removeEvent = function(o, t, f, l)
     {
      var d = 'removeEventListener';
      if (o[d] && !l) return o[d](t, f, false);
      if (o._evts && o._evts[t] && f._i) delete o._evts[t][f._i];
     };
    };
      

  11.   


    看这个很混淆后的差不多了- -
    貌似模拟了个多投不过我到是不太喜欢,修改dom object和function的属性:D
      

  12.   


    /shuai,没测过这种东西只知道循环引用。
    有没好的介绍。。
    好比。。var AE = function (element, type, listener) {
    if (element.addEventListener) {
    return element.addEventListener(type.substr(2), listener, false);
    } else if (element.attachEvent) {
    var listeners = function () {
    listener.apply(element);
    };
    element.attachEvent(type, listeners);
    //element = null;
    }
    };这段代码后泄露么
      

  13.   

    反正IE下循环引用到是肯定有了(在attachEvent会造成循环的情况下,不过我到是觉得它不会因为它的this是window,感觉是在捕获阶段才触发到的listener