addLoadEvents 这个函数的原理

JS新手请问大家addLoadEvents的原理是什么?

    <script>

        window.onload = function(){
            console.log("这个是window.onload默认的绑定事件.")
        }

        function addLoadEvents(fn){
            var oldEvents = window.onload;
            if(typeof oldEvents != 'function'){
                window.onload = fn;
            }else{
                window.onload = function(){
                    oldEvents();
                    fn();
                }
            }
        }

        function fn1(){
            console.log("这个是追加fn1");
        }        
        function fn2(){
            console.log("这个是追加fn2");
        }        
        function fn3(){
            console.log("这个是追加fn3");
        }

        addLoadEvents(fn1);
        addLoadEvents(fn2);
        addLoadEvents(fn3);
    </script>

这个是打印结果:是正常的而且令人满意的.

这个是window.onload默认的绑定事件.
这个是追加fn1
这个是追加fn2
这个是追加fn3

但是从代码运行来看打印的结果应该是这样的呀:

这个是window.onload默认的绑定事件.
这个是追加fn1
这个是window.onload默认的绑定事件.
这个是追加fn2
这个是window.onload默认的绑定事件.
这个是追加fn3

为什么很巧妙的规避默认window.onload事件函数的重复执行了呢? 麻烦大家,谢谢!

阅读 3.2k
3 个回答

其实也不巧妙吧,刚才看得有点懵逼。

var i=0;

        window.onload = function(){
                    console.log(i);
            console.log("这个是window.onload默认的绑定事件.")
        }

        function addLoadEvents(fn){
                    i++;
            var oldEvents = window.onload;
            if(typeof oldEvents != 'function'){
                window.onload = fn;
            }else{
                window.onload = function(){
                    oldEvents();
                    fn();
                }
            }
        }

        function fn1(){
            console.log("这个是追加fn1");
        }        
        function fn2(){
            console.log("这个是追加fn2");
        }        
        function fn3(){
            console.log("这个是追加fn3");
        }

        addLoadEvents(fn1);
        addLoadEvents(fn2);
        addLoadEvents(fn3);

试着用一个i来记录,才意识到,这个onload就执行了一次,因为addLoadEvents把onload回调改写了:先执行前一个onload回调,然后再执行新回调。
所以代码一走下来,就是 默认的回调+fn1的执行+fn2+fn3
所以可以看到执行结果是

3
这个是window.onload默认的绑定事件.
这个是追加fn1
这个是追加fn2
这个是追加fn3

因为在运行addLoadEvents(fn2)的时候取到的oldEvents的结果里面就包含了fn1()。依此类推,自然就是你说的那个结果。

最后,这个叫桥接模式。

-------------------------------------------------------补充-----------------------------------------------------

要实现你提到的那种效果(虽然你可能认为是错误的效果,但是我还是实现一下吧),如下:

var events = [];

function on(obj, type, handler) {
    // 检查obj和type....
    // 总之有这里非常多的验证工作先和细节先省略了
    events.push({
        obj: obj,
        type: type,
        handlerByOn: handler // 通过on的方式添加的handler
    });

    obj.addEventListener(type, function() {
        events.forEach(function(e) { // 这里要检验events中与obj相符,也省略了
            e.handlers.forEach(function(hd) {
                hd();
            });
        });
    });
}

function addLoadEvents(obj, type, handler){
    var oldEvent = events.find(function(e) {return e.obj === obj && e.type === type;});

    var newHandler = function() {
        oldEvent.handlerByOn();
        handler();
    };

    oldEvent && oldEvent.handlers ? oldEvent.handlers.push(newHandler) : oldEvent.handlers = [newHandler];
}

function fn1(){
    console.log("这个是追加fn1");
}
function fn2(){
    console.log("这个是追加fn2");
}
function fn3(){
    console.log("这个是追加fn3");
}

on(window, 'load', function() {
    console.log("这个是window.onload默认的绑定事件.")
});

addLoadEvents(window, 'load', fn1);
addLoadEvents(window, 'load', fn2);
addLoadEvents(window, 'load', fn3);

运行结果如图:

个人理解这里跟window.onload执行机制有关,onload会等到页面dom,图片,音视频,js等都加载解析完成才会执行,因此三个addLoadEvents函数都是在往window.onload里添加函数,最后js解析完成开始执行window.onload

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题