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);
}
}
}
网友评论