《JS编程全解》—— 回调函数

回调函数情势

回调函数与掌握反转

回调函数是程序设想的一种要领。这类要领是指,在通报了可能会举行挪用的函数或对象以后,在须要时再分别对其举行挪用。因为挪用方与被挪用方的依靠关联与一般相反,所以也成为掌握反转(IoC,Inversion of Control)。
因为汗青缘由,在JavaScript开辟中我们经常会用到回调函数这一要领,这是多种要素致使的。第一个缘由是在客户端JavaScript中基础都是GUI程序设想。GUI程序设想是一种很合适运用所谓事宜驱动的程序设想体式格局。事宜驱动恰是一种回调函数设想情势。客户端JavaScript程序设想是一种基于DOM的事宜驱动式程序设想。
第二个缘由是,源于客户端没法完成多线程程序设想(近来HTML5 Web Works支撑多线程了)。而经由过程将回调函数与异步处置惩罚相结合,就能够完成并行处置惩罚。因为不支撑多线程,所以为了完成并行处置惩罚,不得不运用回调函数,这逐步成为了一种通例。末了一个缘由与JavaScript中的函数声明表达式和闭包有关。

JavaScript与回调函数

    var emitter = {
        // 为了能够注册多个回调函数而经由过程数组治理
        callbacks:[],
        // 回调函数的注册要领
        register:function (fn) {
            this.callbacks.push(fn);
        },
        // 事宜的触发处置惩罚
        onOpen:function () {
            for (var f in this.callbacks) {
                this.callbacks[f]();
            }
        }
    };
    emitter.register(function () {alert("event handler1 is called");})
    emitter.register(function () {alert("event handler2 is called");})
    
    emitter.onOpen();    
    // "event handler1 is called"
    // "event handler2 is called"

定义的两个匿名函数就是回调函数,它们的挪用由emitter.onOpen()完成。

 对emitter来讲,这仅仅是对注册的函数举行了挪用,不过依据回调函数的定义,更应该关注运用了emitter部份的状况。从这个角度来看,注册过的回调函数与之构成的是一种挪用与被挪用的关联。

上面的回调函数只是纯真的函数而不具有状况。假如回调函数具有状况,就能够获得更加普遍的运用。下面我们把回调方改为了对象,因而emitter变为了接收要领通报的情势。

    function MyClass(msg) {
        this.msg = msg;
        this.show = function () {alert(this.msg+' is called');}
    }
    // 将要领注册为回调函数
    var obj = new MyClass("listener1");
    var obj2 = new MyClass("listener2");
    emitter.register(obj.show);
    emitter.register(obj2.show);
    
    emitter.onOpen();
    // undefined is called
    // undefined is called

我们发明,挪用回调函数没法准确显现this.msg,毛病缘由在于JavaScript内的this援用。解决要领有两种,一种是运用bind,一种是不运用要领而是用对象举行注册。后者在JavaScript中并不经常使用。

    emitter.register(obj.show.bind(obj));
    emitter.register(obj2.show.bind(obj2));
    
    emitter.onOpen();
    // "listener1 is called"
    // "listener2 is called"

bind是ES5新增的功用,是Function.prototype对象的要领。bind的作用和apply与call雷同,都是用于明白指定出要领挪用时的this援用。关于函数来讲,挪用了bind以后会返回一个新函数,新的函数会实行与原函数雷同的内容,不过其this援用是被指定为它的第一个参数的对象。在挪用apply与call时将会马上挪用目的函数,而在挪用bind时则不会云云,而是会返回一个函数(闭包)。
假如运用了apply或call,就能够对bind举行自力的完成。事实上在ES5才推出之前,在prototype.js等着名的库中就经由过程apply/call供应了bind本身的完成。

脑补的bind的内部完成?

    Function.prototype.bind = null;
    Function.prototype.bind = function (obj) {
        var f = this;
        return function () {
            f.call(obj);
        }
    }
    var obj = {
        x:"这是    obj.x    !!!",
        fn:function () {
            alert(this.x);
        }
    };
    var obj2 = {x:"obj2.x    对啦!!!"};
    
    var testfn = obj.fn.bind(obj2);
    testfn();    // "obj2.x    对啦!!!"

闭包与回调函数

    emitter.register(
        (function () {
            var msg = "closure1";
            return function () {alert(msg+" is called;")};
        }())
    );
    emitter.register(
        (function () {
            var msg = "closure2";
            return function () {alert(msg+" is called;")};
        }())
    )
    
    emitter.onOpen();
    // "closure1 is called"
    // "closure2 is called"

借助闭包,前面繁复的申明似乎不在存在,能够很轻松的完成回调函数,而且还能像对象一样具有状况。

    原文作者:Queen
    原文地址: https://segmentfault.com/a/1190000009800466
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞