backbone事件原理

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);
            }
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,302评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,563评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,433评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,628评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,467评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,354评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,777评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,419评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,725评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,768评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,543评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,387评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,794评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,032评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,305评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,741评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,946评论 2 336