美文网首页
backbone事件原理

backbone事件原理

作者: juceyjing | 来源:发表于2018-03-06 19:32 被阅读19次

    backbone Events
    backbone的Events是一个对象,其中的方法(on\listenTo\off\stopListening\once\listenToOnce\trigger)都是对象方法。
    总体上,backbone的Events实现了监听/触发/解除对自己对象本身的事件,也可以让一个对象监听/解除监听另外一个对象的事件。
    绑定对象自身的监听事件on
    on绑定有三种方式,可以通过对传入参数的不同在进行不同的处理。
    监听其他对象的事件listenTo
    backbone支持监听其他对象的文件
    B对象上面发生b事件的时候,通知A调用回调函数
    A.listenTo(B,'b',callback);

    这和B监听自己的事件,并且在回调函数的时候把上下文变成A差不多。
    首先A有一个A._listeningTo属性,这个属性是一个对象,存放着他监听一个对象的信息。

    on && listenTo 区别

    控制反转
    A.listenTo(B,'b',callback);
    B对象之前控制的事件,现在交由A事件进行控制。

    listenTo 比 on的好的方式在于可以一次性进行解绑。

    var view={
        dosomething:function(some){
    //        ...
        }
    }
    model.on('change:some',view.dosomething,view);
    model2.on('change:some',view.dosomething,view);
    
    //on解绑
        model.off('change:some',view.dosomething,view);
        model2.off('change:some',view.dosomething,view);
    //  listenTo
    view.listenTo(model,'change:some',view.dosomething);
    view.listenTo(model2,'change:some',view.dosomething);
    //listenTo解绑
    view.stopListening();
    

    解除绑定事件off 、stopListening
    与on不同,off的三个参数都是可选的
    如果没有任何参数,off相当于把对应的_events对象整体清空
    如果有name参数但是没有具体指定哪个callback的时候,则把这个name(事件)对应的回调队列全部清空
    如果还有进一步详细的callback和context,那么这个时候移除回调函数非常严格,必须要求上下文和原来函数完全一致
    A监听了B点一个事件,意味着
    A._listenTo中就会多一个条目,存储这个监听事件的信息。
    B._listener也会多一个条目。

    触发trigger函数 ---的实现原理?未解析

    // Trigger one or many events, firing all bound callbacks. Callbacks are
      // passed the same arguments as `trigger` is, apart from the event name
      // (unless you're listening on `"all"`, which will cause your callback to
      // receive the true name of the event as the first argument).
      Events.trigger =  function(name) {
        if (!this._events) return this;
    
        var length = Math.max(0, arguments.length - 1);
        var args = Array(length);
        for (var i = 0; i < length; i++) args[i] = arguments[i + 1];
    
        eventsApi(triggerApi, this._events, name, void 0, args);
        return this;
      };
    
      // Handles triggering the appropriate event callbacks.
      var triggerApi = function(objEvents, name, cb, args) {
        if (objEvents) {
          var events = objEvents[name];
          var allEvents = objEvents.all;
          if (events && allEvents) allEvents = allEvents.slice();
          if (events) triggerEvents(events, args);
          if (allEvents) triggerEvents(allEvents, [name].concat(args));
        }
        return objEvents;
      };
      // A difficult-to-believe, but optimized internal dispatch function for
      // triggering events. Tries to keep the usual cases speedy (most internal
      // Backbone events have 3 arguments).
      var triggerEvents = function(events, args) {
        var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
        switch (args.length) {
          case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
          case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
          case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
          case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
          default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
        }
      };
    

    setTimeout()异步调用,js运行环境为单线程,setTimeout注册的函数需要等待线程空闲才能执行,此时for循环已经结束,
    为5,将setTimeout放到函数立即调用的表达式中,将值作为参数传递给包裹函数。

    for(var i=0;i<5;++i){
        setTimeout(function(){
            console.log(i)
        },100)  
    }
    
      for(var i=0;i<5;++i){
        (function(i){
            setTimeout(function(){
                console.log(i)
        },500)}(i)) 
    }
    

    如何判断一个对象是否为数组

      Array.isArray(data)
        Object.prototype.toString.call(data)
        function isArray(arg){
            if(typeof arg==='object'){
                return Object.prototype.toString.call(arg)==='[object Array]'
    }
    return false;
        }
    

    回调函数的例子:

    var friends = ["Mike", "Stacy", "Andy", "Rick"];
    friends.forEach(function (eachName, index) {
        console.log(index+1+'.'+eachName);
    })
    

    这个匿名函数当做参数传递给了forEach()方法,我们像对待对象一样对待函数。
    当我们将一个回调函数作为参数传递给另一个函数时,我们仅仅传递了函数的定义。
    并没有在参数中执行函数。需要注意的是回调函数并不会马上执行,他会在包含他的函数内的某个时间点被回调。

    $('#btn1').click(function(){
        alert('btn 1 Clicked!')
    })
    

    这个匿名函数会在函数体内被调用。

    回调函数时闭包

    我们将一个回调函数作为变量传递给一个函数时,这个回调在函数的某个时间段执行,好像是包含在他的函数定义中的一样。
    这意味这回调函数本质上来讲是一个闭包。
    正如闭包可以访问父级作用域一样,回调函数可以能获取包含他函数的变量以及全局变量。

    实现回调函数的基本原理

    执行前确保回调函数时一个函数 typeof =='function'

    jsonp实现

    1.jsonp是一种跨域通信的手段:

    1.利用script标签的src属性来实现跨域
    2.通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数后再返回,实现服务端向客户端通信。
    3.由于使用script标签的src属性,因此只支持get方法

    2.实现流程

    1.设定一个script标签

    function jsonp(res){
    var script=document.createElement("script");
    var url=url+"?callback="+res.callback.name
    script.src=url;}
    jsonp({
        url:"xxx",
        data:'',
        callback:fn
    })
    

    jsonp现在不常用,用core配合服务端更多一些;
    浅拷贝的方法有两个:
    1.var new_arr=arr.slice();
    2.var new_arr=arr.concat();

    深拷贝
    var new_arr = JSON.parse(JSON.stringify(arr));

         function extend() {
            // 默认不进行深拷贝
            var deep = false;
            var name, options, src, copy, clone, copyIsArray;
            var length = arguments.length;
            // 记录要复制的对象的下标
            var i = 1;
            // 第一个参数不传布尔值的情况下,target 默认是第一个参数
            var target = arguments[0] || {};
            // 如果第一个参数是布尔值,第二个参数是 target
            if (typeof target == 'boolean') {
                deep = target;
                target = arguments[i] || {};
                i++;
            }
            // 如果target不是对象,我们是无法进行复制的,所以设为 {}
            if (typeof target !== "object" && !isFunction(target)) {
                target = {};
            }
    
            // 循环遍历要复制的对象们
            for (; i < length; i++) {
                // 获取当前对象
                options = arguments[i];
                // 要求不能为空 避免 extend(a,,b) 这种情况
                if (options != null) {
                    for (name in options) {
                        // 目标属性值
                        src = target[name];
                        // 要复制的对象的属性值
                        copy = options[name];
    
                        // 解决循环引用
                        if (target === copy) {
                            continue;
                        }
    
                        // 要递归的对象必须是 plainObject 或者数组
                        if (deep && copy && (isPlainObject(copy) ||
                                (copyIsArray = Array.isArray(copy)))) {
                            // 要复制的对象属性值类型需要与目标属性值相同
                            if (copyIsArray) {
                                copyIsArray = false;
                                clone = src && Array.isArray(src) ? src : [];
    
                            } else {
                                clone = src && isPlainObject(src) ? src : {};
                            }
    
                            target[name] = extend(deep, clone, copy);
    
                        } else if (copy !== undefined) {
                            target[name] = copy;
                        }
                    }
                }
            }
    
            return target;
        };
    //    自定义事件(通过观察者模式)
    function EventTarget () {
        this.handlers = {};
    }
    
        EventTarget.prototype = {
            constructor: EventTarget,
            addHandler: function (type, handler) {
                if (typeof this.handlers[type] == 'undefined') {
                    this.handlers[type] = [];
                }
                this.handlers[type].push(handler)
            },
            fire: function (event) {
                if (!event.target) {
                    event.target = this;
                }
                if (this.handlers[event.type] instanceof Array) {
                    var handlers = this.handlers[event.type];
                    for (var i = 0, len = handlers.length; i < len; i++) {
                        handlers[i](event);
                    }
                }
            },
            removeHandler: function (type, handler) {
                if (this.handlers[type] instanceof Array) {
                    var handlers = this.handlers[type];
                    for (var i = 0, len = handlers.length; i < len; i++) {
                        if (handlers[i] === handler) {
                            break;
                        }
                    }
                    handlers.splice(i, 1);
                }
            }
        }
    

    相关文章

      网友评论

          本文标题:backbone事件原理

          本文链接:https://www.haomeiwen.com/subject/qqihnxtx.html