的观察者情势,js寓目者方式学习计算

座谈 JavaScript 的观望者情势(自定义事件)

2016/08/25 · JavaScript
·
观望者格局,
设计格局

正文小编: 伯乐在线 –
winty
。未经小编许可,禁止转发!
欢迎参预伯乐在线 专栏撰稿人。

萧萧,前不久出席了一个笔试,里面有一到JS编程题,当时看着难题就蒙圈。后来研商了眨眼之间间,原来就是所谓的寓目者情势。就记下来
^_^

题目

JavaScript

[附加题] 请完毕上面的自定义事件 伊芙nt 对象的接口,功能见注释(测试1) 该
伊夫nt 对象的接口必要能被其他对象举行复用(测试2) // 测试1
伊夫nt.on(‘test’, function (result) { console.log(result); });
伊夫nt.on(‘test’, function () { console.log(‘test’); });
伊夫nt.emit(‘test’, ‘hello world’); // 输出 ‘hello world’ 和 ‘test’ //
测试2 var person1 = {}; var person2 = {}; Object.assign(person1, 伊夫nt);
Object.assign(person2, 伊夫nt); person1.on(‘call1’, function () {
console.log(‘person1’); }); person2.on(‘call2’, function () {
console.log(‘person2’); }); person1.emit(‘call1’); // 输出 ‘person1’
person1.emit(‘call2’); // 没有出口 person2.emit(‘call1’); // 没有出口
person2.emit(‘call2’); // 输出 ‘person2′<br>var 伊夫nt = { //
通过on接口监听事件eventName //
即使事件eventName被触发,则实施callback回调函数 on: function (eventName,
callback) { //你的代码 }, // 触发事件 eventName emit: function
(eventName) { //你的代码 } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[附加题] 请实现下面的自定义事件 Event 对象的接口,功能见注释(测试1)
该 Event 对象的接口需要能被其他对象拓展复用(测试2)
// 测试1
Event.on(‘test’, function (result) {
    console.log(result);
});
Event.on(‘test’, function () {
    console.log(‘test’);
});
Event.emit(‘test’, ‘hello world’); // 输出 ‘hello world’ 和 ‘test’
// 测试2
var person1 = {};
var person2 = {};
Object.assign(person1, Event);
Object.assign(person2, Event);
person1.on(‘call1’, function () {
    console.log(‘person1’);
});
person2.on(‘call2’, function () {
    console.log(‘person2’);
});
person1.emit(‘call1’); // 输出 ‘person1’
person1.emit(‘call2’); // 没有输出
person2.emit(‘call1’); // 没有输出
person2.emit(‘call2’); // 输出 ‘person2′<br>var Event = {
    // 通过on接口监听事件eventName
    // 如果事件eventName被触发,则执行callback回调函数
    on: function (eventName, callback) {
        //你的代码
    },
    // 触发事件 eventName
    emit: function (eventName) {
        //你的代码
    }
};

差不多没把自身看晕…

好啊,一步一步来探望怎么回事。

①打听一下寓目者格局

观望者情势

那是一种创设松散耦合代码的技能。它定义对象间
一种一对多的依靠关系,当一个对象的情形爆发转移时,所有信赖于它的对象都将获取公告。由中央和观看者组成,主体各负其责发表事件,同时观看者通过订阅那一个事件来观看该中央。主体并不知佛殿看者的其余业务,观看者知道主体并能注册事件的回调函数。

例子:

如若我们正在开发一个百货集团网站,网站里有header底部、nav导航、信息列表、购物车等模块。那多少个模块的渲染有一个共同的前提条件,就是必须先用ajax异步请求获取用户的记名信息。那是很正规的,比如用户的名字和头像要出示在header模块里,而那多个字段都源于用户登录后赶回的消息。这么些时候,大家就足以把那多少个模块的渲染事件都放置一个数组里面,然后待登录成功之后再遍历这一个数组并且调用每一个主意。

基本形式:

JavaScript

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);
} } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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);
          }
      }
};

大概意思就是,创制一个事件管理器。handles是一个储存事件处理函数的对象。

addHandle:是丰硕事变的办法,该措施接收七个参数,一个是要加上的事件的品种,一个是其一事件的回调函数名。调用的时候会率先遍历handles那一个目的,看看这几个类其余章程是否业已存在,假诺已经存在则添加到该数组,倘使不存在则先创建一个数组然后拉长。

fire方法:是进行handles那一个目标里面的某个项指标每一个办法。

removeHandle:是对应的删除函数的主意。

好啊,回到标题,分析一下。

②标题中的测试一:

JavaScript

// 测试1 Event.on(‘test’, function (result) { console.log(result); });
Event.on(‘test’, function () { console.log(‘test’); });
Event.emit(‘test’, ‘hello world’); // 输出 ‘hello world’ 和 ‘test’

1
2
3
4
5
6
7
8
// 测试1
Event.on(‘test’, function (result) {
    console.log(result);
});
Event.on(‘test’, function () {
    console.log(‘test’);
});
Event.emit(‘test’, ‘hello world’); // 输出 ‘hello world’ 和 ‘test’

意思就是,定义一个叫’test’类型的事件集,并且注册了多个test事件。然后调用test事件集里面的上上下下办法。在那里on方法等价于addHandle方法,emit方法等价于fire方法。其中第二个参数就是事件类型,首个参数就是要传进函数的参数。

是不是其四遍事呢?很好,那么我们要写的代码就是:

JavaScript

var 伊夫nt = { // 通过on接口监听事件eventName //
假设事件eventName被触发,则履行callback回调函数 on: function (eventName,
callback) { //我的代码 if(!this.handles){ this.handles={}; }
if(!this.handles[eventName]){ this.handles[eventName]=[]; }
this.handles[eventName].push(callback); }, // 触发事件 eventName emit:
function (eventName) { //你的代码 if(this.handles[arguments[0]]){
for(var i=0;i<this.handles[arguments[0]].length;i++){
this.handles[arguments[0]][i](arguments[1]); } } } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var Event = {
    // 通过on接口监听事件eventName
    // 如果事件eventName被触发,则执行callback回调函数
    on: function (eventName, callback) {
        //我的代码
        if(!this.handles){
             this.handles={};    
        }      
       if(!this.handles[eventName]){
            this.handles[eventName]=[];
       }
       this.handles[eventName].push(callback);
    },
    // 触发事件 eventName
    emit: function (eventName) {
        //你的代码
       if(this.handles[arguments[0]]){
           for(var i=0;i<this.handles[arguments[0]].length;i++){
               this.handles[arguments[0]][i](arguments[1]);
           }
       }
    }
};

如此那般测试,完美地经过了测试一。

③测试二:

JavaScript

var person1 = {}; var person2 = {}; Object.assign(person1, 伊芙nt);
Object.assign(person2, 伊夫nt); person1.on(‘call1’, function () {
console.log(‘person1’); }); person2.on(‘call2’, function () {
console.log(‘person2’); }); person1.emit(‘call1’); // 输出 ‘person1’
person1.emit(‘call2’); // 没有出口 person2.emit(‘call1’); // 没有出口
person2.emit(‘call2’); // 输出 ‘person2’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var person1 = {};
var person2 = {};
Object.assign(person1, Event);
Object.assign(person2, Event);
person1.on(‘call1’, function () {
    console.log(‘person1’);
});
person2.on(‘call2’, function () {
    console.log(‘person2’);
});
person1.emit(‘call1’); // 输出 ‘person1’
person1.emit(‘call2’); // 没有输出
person2.emit(‘call1’); // 没有输出
person2.emit(‘call2’); // 输出 ‘person2’

大概意思就是为多个分裂person注册自定义事件,并且多少个person之间是并行独立的。

一贯测试,发现输出了

亚洲必赢官网 1

其一类似是题材要求有些出入呢,或者那才是难题的坑吧!

解释一下,Object.assign(person1, Event);

这几个是ES6的新目的方法,用于对象的合并,将源对象(source)的具备可枚举属性,复制到目标对象(target)。

趣味是将伊夫nt里面的可枚举的目的和格局放到person1里面。

亚洲必赢官网 2

也就是说,如若源对象某个属性的值是目的,那么目的对象拷贝获得的是那个目的的引用。由于开展测试一的时候调用了on方法,所以event里面早已有了handles这几个可枚举的习性。然后再分别合并到多少个person里面的话,四个person对象里面的handles都只是一个引用。所以就竞相影响了。

假设assign方法要贯彻深克隆则要这样:

亚洲必赢官网 3

标题是,标题已经稳定了章程,大家无法修改那几个办法。

据此,大家无法不将handles那么些特性定义为恒河沙数的,然后在person调用on方法的时候再分别爆发handles这一个目标。

也就是说正确的做法应该是:

JavaScript

var 伊芙nt = { // 通过on接口监听事件eventName //
倘诺事件eventName被触发,则实施callback回调函数 on: function (eventName,
callback) { //你的代码 if(!this.handles){ //this.handles={};
Object.defineProperty(this, “handles”, { value: {}, enumerable: false,
configurable: true, writable: true }) } if(!this.handles[eventName]){
this.handles[eventName]=[]; }
this.handles[eventName].push(callback); }, // 触发事件 eventName emit:
function (eventName) { //你的代码 if(this.handles[arguments[0]]){
for(var i=0;i<this.handles[arguments[0]].length;i++){
this.handles[arguments[0]][i](arguments[1]); } } } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var Event = {
    // 通过on接口监听事件eventName
    // 如果事件eventName被触发,则执行callback回调函数
    on: function (eventName, callback) {
        //你的代码
        if(!this.handles){
            //this.handles={};
            Object.defineProperty(this, "handles", {
                value: {},
                enumerable: false,
                configurable: true,
                writable: true
            })
        }
      
       if(!this.handles[eventName]){
            this.handles[eventName]=[];
       }
       this.handles[eventName].push(callback);
    },
    // 触发事件 eventName
    emit: function (eventName) {
        //你的代码
       if(this.handles[arguments[0]]){
           for(var i=0;i<this.handles[arguments[0]].length;i++){
               this.handles[arguments[0]][i](arguments[1]);
           }
       }
    }
};

由此那道题,感觉考得真的很巧妙而且很考基础。好啊。我要么好好复习去了。

打赏协理自己写出越来越多好小说,谢谢!

打赏小编

观望者格局:

那是一种创设松散耦合代码的技能。它定义对象间
一种一对多的看重关系,当一个对象的境况爆发转移时,所有信赖于它的靶子都将得到公告。由中央和观望者组成,主体各负其责发布事件,同时观看者通过订阅那一个事件来察看该中央。主体并不知道寓目者的任何事情,观看者知道主体并能注册事件的回调函数。

node事件
<code>
server.on(‘connection’, (stream) => {
console.log(‘someone connected!’);
});
server.removeListener(‘connection’, callback);
server.emit(‘connection’, callback);
</code>
<p>
node 在一个事件之中只好登记10个事件
</p>

# Backbone入门之事件(Backbone.伊夫nts)

介绍

打赏帮衬我写出更加多好小说,谢谢!

任选一种支付办法

亚洲必赢官网 4
亚洲必赢官网 5

1 赞 5 收藏
评论

兑现它的效果

挂号与发布
<code>
function Events(name) {
this.name = name;
this._events = {};
}
Events.prototype.on = function(eventname, callback) {
if(this._events[eventname]) {
this._events[eventname].push(callback)
}else{
this._events[eventname]=[callback]
}
}
Events.prototype.emit=function(eventname){
var callbacks=this._events[eventname]
callbacks.forEach(function(callback){
callback()
})
}
var girl = new Events()
girl.on(‘长发及腰’,function(){
的观察者情势,js寓目者方式学习计算。console.log(‘长发及腰’)
})
girl.on(‘长发及腰’,function(){
console.log(‘长发及腰2’)
})
girl.emit(‘长发及腰’)
</code>

本连串前一篇讲述了[Backbone入门之视图](

观望者格局又叫公布订阅方式(Publish/Subscribe),它定义了一种一对多的涉及,让八个观看者对象同时监听某一个主旨对象,这一个大旨对象的事态暴发变化时就会通报所有的观看者对象,使得它们能够自动更新自己。

有关笔者:winty

亚洲必赢官网 6

前者工程师,前端爱好者。博客:

个人主页 ·
我的作品 ·
1 ·
 

亚洲必赢官网 7

神话是阿里面试题 完毕效益

<code>
const emitter = new EventEmitter()
const sayHi = (name) => console.log(Hello ${name})
const sayHi2 = (name) => console.log(Good night, ${name})
emitter.on(‘hi’, sayHi)
emitter.on(‘hi’, sayHi2)
emitter.emit(‘hi’, ‘ScriptOJ’)
// => Hello ScriptOJ
// => Good night, ScriptOJ
emitter.off(‘hi’, sayHi)
emitter.emit(‘hi’, ‘ScriptOJ’)
// => Good night, ScriptOJ
const emitter2 = new EventEmitter()
emitter2.on(‘hi’, (name, age) => {
console.log(I am ${name}, and I am ${age} years old)
})
emitter2.emit(‘hi’, ‘Jerry’, 12)
// => I am Jerry, and I am 12 years old
</code>

Backbone事件将事件触发所要实践的回调函数注册成事件处理句柄,当事件爆发时,就触发该函数。

选用观望者格局的益处:

兑现它的功能

登记与揭橥
<code>
function EventEmitter(name) {
this.name = name;
this._events = {};
}
EventEmitter.prototype.on = function(eventname, callback) {
if(this._events[eventname]) {
this._events[eventname].push(callback)
} else {
this._events[eventname] = [callback]
}
}
EventEmitter.prototype.emit = function(eventname) {
var args = Array.prototype.slice.call(arguments, 1)
var callbacks = this._events[eventname]
var self = this
callbacks.forEach(function(callback) {
callback.apply(self, args)
})
}
EventEmitter.prototype.off = function(eventname, callback) {
var callbacks = this._events[eventname]
let cbindex = callbacks.indexOf(callback)
if(cbindex === -1) {
console.log(‘没有该方法’)
} else {
callbacks.splice(cbindex, 1);
}
}
const emitter = new EventEmitter()
const sayHi = (name) => console.log(Hello ${name})
const sayHi2 = (name) => console.log(Good night, ${name})

emitter.on(‘hi’, sayHi)
emitter.on(‘hi’, sayHi2)
emitter.emit(‘hi’, ‘ScriptOJ’)
Hello ScriptOJ
Good night, ScriptOJ

emitter.off(‘hi’, sayHi)
emitter.off(‘hi’, sayHi3)
emitter.emit(‘hi’, ‘ScriptOJ’)
Good night, ScriptOJ

const emitter2 = new EventEmitter()
emitter2.on(‘hi’, (name, age) => {
console.log(I am ${name}, and I am ${age} years old)
})
emitter2.emit(‘hi’, ‘Jerry’, 12)
</code>

ES6 class方法
<code>
class EventEmitter {
constructor(name) {
this.name = name;
this._events = {};
}
on(eventname, callback) {
if(this._events[eventname]) {
this._events[eventname].push(callback)
} else {
this._events[eventname] = [callback]
}
}
emit(eventname, …args) {
let callbacks = this._events[eventname]
callbacks.forEach(function(callback) {
callback(args)
})
}
off(eventname,cb){
let callbacks = this._events[eventname];
let cbindex=callbacks.indexOf(cb)
if(cbindex===-1){
console.log(‘该方法不存在’)
}else{
callbacks.splice(cbindex,1)
}
}
}
const emitter = new EventEmitter()
const sayHi = (name) => console.log(Hello ${name})
const sayHi2 = (name) => console.log(Good night, ${name})
emitter.on(‘hi’, sayHi)
emitter.on(‘hi’, sayHi2)
emitter.emit(‘hi’, ‘ScriptOJ’)
emitter.off(‘hi’, sayHi)
emitter.off(‘hi’, ‘sayHi3’)
emitter.emit(‘hi’, ‘ScriptOJ’)
const emitter2 = new EventEmitter()
emitter2.on(‘hi’, (name, age) => {
console.log(I am ${name}, and I am ${age} years old)
})
emitter2.emit(‘hi’, ‘Jerry’, 12)</code>

## Backbone.Events

1.支撑不难的播音通讯,自动公告所有曾经订阅过的靶子。
2.页面载入后目的对象很不难与观察者存在一种动态关联,扩充了灵活性。
3.目的对象与观看者之间的虚幻耦合关系可以单独增加以及重用。

redux 使用阅览情势代码

<code>
let currentListeners = []
let nextListeners = currentListeners
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
function subscribe(listener) {
if (typeof listener !== ‘function’) {
throw new Error(‘Expected listener to be a function.’)
}
//判断是还是不是是函数
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
isSubscribed = false
ensureCanMutateNextListeners()
亚洲必赢官网 ,const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}

每几次实践dispath 都会进行监听函数
function dispatch(action) {
if (!isPlainObject(action)) {
throw new Error(
‘Actions must be plain objects. ‘ +
‘Use custom middleware for async actions.’
)
}
if (typeof action.type === ‘undefined’) {
throw new Error(
‘Actions may not have an undefined “type” property. ‘ +
‘Have you misspelled a constant?’
)
}
if (isDispatching) {
throw new Error(‘Reducers may not dispatch actions.’)
}
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = currentListeners = nextListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
</code>

统计,写东西真累,将来会习惯的。。。

Backbone.伊芙nts可以伸张到其它对象上,使其有着绑定和接触事件的能力。在绑定事件的回调处理函数此前,不须求定义事件,且可以传递参数:

正文(版本一)

“`

JS里对观望者方式的兑现是透过回调来落实的,大家来先定义一个pubsub对象,其里面含有了3个主意:订阅、退订、发布。

   var myObj = {};

复制代码 代码如下:

   _.extend(myObj, Backbone.Events);

var pubsub = {};
(function (q) {
 
    var topics = {}, // 回调函数存放的数组
        subUid = -1;
    // 公布办法
    q.publish = function (topic, args) {
 
        if (!topics[topic]) {
            return false;
        }
 
        setTimeout(function () {
            var subscribers = topics[topic],
                len = subscribers ? subscribers.length : 0;
 
            while (len–) {
                subscribers[len].func(topic, args);
            }
        }, 0);
 
        return true;
 
    };
    //订阅方法
    q.subscribe = function (topic, func) {
 
        if (!topics[topic]) {
            topics[topic] = [];
        }
 
        var token = (++subUid).toString();
        topics[topic].push({
            token: token,
            func: func
        });
        return token;
    };
    //退订方法
    q.unsubscribe = function (token) {
        for (var m in topics) {
            if (topics[m]) {
                for (var i = 0, j = topics[m].length; i < j; i++)
{
                    if (topics[m][i].token === token) {
                        topics[m].splice(i, 1);
                        return token;
                    }
                }
            }
        }
        return false;
    };
} (pubsub));

   //添加一个自定义事件

运用格局如下:

   myObj.on(‘test’, function(msg) {

复制代码 代码如下:

       console.log(‘triggered ‘ + msg);

//来,订阅一个
pubsub.subscribe(‘example1’, function (topics, data) {
    console.log(topics + “: ” + data);
});
 
//宣布公告
pubsub.publish(‘example1’, ‘hello world!’);
pubsub.publish(‘example1’, [‘test’, ‘a’, ‘b’, ‘c’]);
pubsub.publish(‘example1’, [{ ‘color’: ‘blue’ }, { ‘text’:
‘hello’}]);

   });

什么?用起来是或不是很爽?然而那种方法有个难点,就是不可能退订订阅,要退订的话无法不指定退订的名称,所以大家再来一个版本:

   //触发自定义事件,输出”triggered test”

复制代码 代码如下:

   myObj.trigger(‘test’, ‘test’);

//将订阅赋值给一个变量,以便退订
var testSubscription = pubsub.subscribe(‘example1’, function (topics,
data) {
    console.log(topics + “: ” + data);
});
 
//发布通报
pubsub.publish(‘example1’, ‘hello world!’);
pubsub.publish(‘example1’, [‘test’, ‘a’, ‘b’, ‘c’]);
pubsub.publish(‘example1’, [{ ‘color’: ‘blue’ }, { ‘text’:
‘hello’}]);
 
//退订
setTimeout(function () {
    pubsub.unsubscribe(testSubscription);
}, 0);
 
//再揭橥四遍,验证一下是或不是还是可以出口新闻
pubsub.publish(‘example1’, ‘hello again! (this will fail)’);

“`

版本二

### on()

咱俩也得以运用原型的特征已毕一个观望者方式,代码如下:

on(event, callback
[,context])会在目的上绑定一个事变回调函数,回调函数this默许指向当前目的,事件时有爆发时,回调函数就会被调用。单一事件时,首个参数event值即为自定义事件名;而多少个事件时,则足以为事件加上命名空间,以冒号分隔;第多个参数可以流传作为回调函数执行上下文,:

复制代码 代码如下:

*注:特殊事件all,可以捕获对象上拥有的事件触发。*

function Observer() {
    this.fns = [];
}
Observer.prototype = {
    subscribe: function (fn) {
        this.fns.push(fn);
    },
    unsubscribe: function (fn) {
        this.fns = this.fns.filter(
                        function (el) {
                            if (el !== fn) {
                                return el;
                            }
                        }
                    );
    },
    update: function (o, thisObj) {
        var scope = thisObj || window;
        this.fns.forEach(
                        function (el) {
                            el.call(scope, o);
                        }
                    );
    }
};
 
//测试
var o = new Observer;
var f1 = function (data) {
    console.log(‘罗布bin: ‘ + data + ‘, 赶紧干活了!’);
};
 
var f2 = function (data) {
    console.log(‘Randall: ‘ + data + ‘, 找她加点薪酬去!’);
};
 
o.subscribe(f1);
o.subscribe(f2);
 
o.update(“Tom回来了!”)
 
//退订f1
o.unsubscribe(f1);
//再来验证
o.update(“Tom回来了!”);

– 未注册all事件

一旦提示找不到filter或者forEach函数,可能是因为您的浏览器还不够新,暂时不协理新规范的函数,你能够应用如下情势自己定义:

   “`

复制代码 代码如下:

       var myObj = {};

if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (fn, thisObj) {
        var scope = thisObj || window;
        for (var i = 0, j = this.length; i < j; ++i) {
            fn.call(scope, this[i], i, this);
        }
    };
}
if (!Array.prototype.filter) {
    Array.prototype.filter = function (fn, thisObj) {
        var scope = thisObj || window;
        var a = [];
        for (var i = 0, j = this.length; i < j; ++i) {
            if (!fn.call(scope, this[i], i, this)) {
                continue;
            }
            a.push(this[i]);
        }
        return a;
    };
}

       _.extend(myObj, Backbone.Events);

版本三

       function test(msg) {

如若想让六个目的都享有观看者揭橥订阅的效率,我们可以定义一个通用的函数,然后将该函数的成效利用到要求观望者作用的目的上,代码如下:

           console.log(‘triggered ‘ + msg);

复制代码 代码如下:

       }

//通用代码
var observer = {
    //订阅
    addSubscriber: function (callback) {
        this.subscribers[this.subscribers.length] = callback;
    },
    //退订
    removeSubscriber: function (callback) {
        for (var i = 0; i < this.subscribers.length; i++) {
            if (this.subscribers[i] === callback) {
                delete (this.subscribers[i]);
            }
        }
    },
    //发布
    publish: function (what) {
        for (var i = 0; i < this.subscribers.length; i++) {
            if (typeof this.subscribers[i] === ‘function’) {
                this.subscribers[i](what);
            }
        }
    },
    // 将对象o具有观看者功能
    make: function (o) {
        for (var i in this) {
            o[i] = this[i];
            o.subscribers = [];
        }
    }
};

       myObj.on(‘test:first’, test);

下一场订阅2个目的blogger和user,使用observer.make方法将那2个对象拥有寓目者功用,代码如下:

       myObj.on(‘test:second’, test);

复制代码 代码如下:

       //触发test:first事件,输出 “triggered test first”

var blogger = {
    recommend: function (id) {
        var msg = ‘dudu 推荐了的帖子:’ + id;
        this.publish(msg);
    }
};
 
var user = {
    vote: function (id) {
        var msg = ‘有人投票了!ID=’ + id;
        this.publish(msg);
    }
};
 
observer.make(blogger);
observer.make(user);

       myObj.trigger(‘test:first’, ‘test first’);

行使方法就比较不难了,订阅差其余回调函数,以便可以挂号到差异的观望者对象里(也可以同时登记到多少个观看者对象里):

       //触发test:second事件,输出 “triggered test second”

复制代码 代码如下:

       myObj.trigger(‘test:second’, ‘test second’);

var tom = {
    read: function (what) {
        console.log(‘Tom看到了之类音讯:’ + what)
    }
};
 
var mm = {
    show: function (what) {
        console.log(‘mm看到了如下消息:’ + what)
    }
};
// 订阅
blogger.addSubscriber(tom.read);
blogger.addSubscriber(mm.show);
blogger.recommend(123); //调用宣布
 
//退订
blogger.removeSubscriber(mm.show);
blogger.recommend(456); //调用发表
 
//此外一个对象的订阅
user.addSubscriber(mm.show);
user.vote(789); //调用发布

       //不触发任何事件

jQuery版本

       myObj.trigger(‘test’, ‘test’);

基于jQuery1.7版新增的on/off成效,大家也得以定义jQuery版的观看者:

   “`

复制代码 代码如下:

– 注册all事件

(function ($) {
 
    var o = $({});
 
    $.subscribe = function () {
        o.on.apply(o, arguments);
    };
 
    $.unsubscribe = function () {
        o.off.apply(o, arguments);
    };
 
    $.publish = function () {
        o.trigger.apply(o, arguments);
    };
 
} (jQuery));

   “`

调用方法比地点3个本子都简短:

       var myObj = {};

复制代码 代码如下:

       _.extend(myObj, Backbone.Events);

//回调函数
function handle(e, a, b, c) {
    // `e`是事件目标,不需求关爱
    console.log(a + b + c);
};
 
//订阅
$.subscribe(“/some/topic”, handle);
//发布
$.publish(“/some/topic”, [“a”, “b”, “c”]); // 输出abc
       
 
$.unsubscribe(“/some/topic”, handle); // 退订
 
//订阅
$.subscribe(“/some/topic”, function (e, a, b, c) {
    console.log(a + b + c);
});
 
$.publish(“/some/topic”, [“a”, “b”, “c”]); // 输出abc
 
//退订(退订使用的是/some/topic名称,而不是回调函数哦,和版本一的事例分化等
$.unsubscribe(“/some/topic”);

       function test(msg) {

可以看出,他的订阅和退订使用的是字符串名称,而不是回调函数名称,所以就是传入的是匿名函数,我们也是足以退订的。

           console.log(‘triggered ‘ + msg);

总结

       }

观看者的行使场馆就是:当一个目标的更改须要同时改变其余对象,并且它不清楚具体有微微对象须求变更的时候,就应当考虑采用观察者情势。

       //监听所有事件

总的看,寓目者方式所做的工作就是在解耦,让耦合的两边都依赖于肤浅,而不是凭借于具体。从而使得个其他变通都不会潜移默化到另一头的变通。

       myObj.on(‘all’, test);

您或许感兴趣的小说:

  • JavaScript设计形式之观看者方式(发表者-订阅者方式)
  • NodeJS设计模式计算【单例情势,适配器形式,装饰情势,寓目者形式】
  • JS设计格局之寓目者格局完结实时改变页面中金额数的不二法门
  • JavaScript编程设计情势之观察者情势(Observer
    Pattern)实例详解
  • js 公布订阅情势的实例讲解
  • node.js
    揭橥订阅形式的实例
  • JavaScript设计格局之工厂方式和浮泛工厂情势定义与用法分析
  • JavaScript设计方式之构造器形式(生成器格局)定义与用法实例分析
  • JavaScript设计格局之单例格局原理与用法实例分析
  • JavaScript设计情势之原型情势分析【ES5与ES6】
  • JavaScript设计情势之观察者情势(公布订阅情势)原理与贯彻方式言传身教

       //触发test:first事件,输出 “triggered test first”

       myObj.trigger(‘test:first’, ‘test first’);

       //触发test:second事件,输出 “triggered test second”

       myObj.trigger(‘test:second’, ‘test second’);

       //触发test事件, 输出”triggered test”

       myObj.trigger(‘test’, ‘test’);

   “`

### once()

登记事件并绑定回调处理函数,触发两次后迅即被移除,其余同on()方法。

### off()

off([event] [,callback]
[,context])事件可以移除从前经过on()方法绑定在事件目的上的回调处理函数,第三个参数为要移除的回调函数对应的事件名,若为空则移除所有事件的回调函数;第三个参数为相应的要移除的回调函数名,若为空则移除该事件负有绑定的回调函数:第多个函数为回调函数上下文,若为空则移除所有上下文下的那几个回调函数:

“`

   var myObj = {};

   _.extend(myObj, Backbone.Events);

   function test(msg) {

       console.log(‘triggered ‘ + msg);

   }

   function joke(msg) {

       console.log(“Joke ” + msg);

   }

   myObj.on(‘test:first’, test);

   myObj.on(‘test:second’, test);

   myObj.on(‘joke’, test);

   myObj.on(‘joke’, joke);

   myObj.off(‘test:first’);

   //触发test:first事件,不输出

   myObj.trigger(‘test:first’, ‘test first’);

   //触发test:second事件,输出 “triggered test second”

   myObj.trigger(‘test:second’, ‘test second’);

   myObj.off(‘joke’, test);

   //触发joke事件,输出”Joke joke”

   myObj.trigger(‘joke’, ‘joke’);

   myObj.off(‘joke’);

   //触发joke事件,不输出

   myObj.trigger(‘joke’, ‘joke’);

“`

### trigger()

trigger(event
[,*args])方法为指定事件触发回调函数,首个参数为事件名,前面的参数为传送的参数,可以为一个或三个;trigger()方法能够触发一个或多少个事件的回调函数,触发单个事件时,event参数值即为事件名;而接触多个事件时,event值为以空格分隔的两个事件名:

“`

   var myObj = {};

   _.extend(myObj, Backbone.Events);

   function test(arg1, arg2) {

       console.log(‘triggered ‘ + arg1 + ‘ ‘ + arg2);

   }

   function joke(msg) {

       console.log(“Joke ” + msg);

   }

   myObj.on(‘test’, test);

   myObj.on(‘joke’, joke);

   //输出”triggered boy girl”

   myObj.trigger(‘test’, ‘boy’, ‘girl’);

   //输出”triggered several events undefined”和”Joke several events”

   myObj.trigger(‘test joke’, ‘several events’);

“`

### listenTo()

前文的on()和off()都是在对象上一贯绑定或移除回调函数,而listenTo(obj,
event,
callback)方法则可以兑现一个目的监听另一个目标上的事件,首个参数是要监听的对象,首个参数是要坚听对象上事件的风云名,第五个参数是所监听目的上事件触发时此目标上的回调函数:

*注:object.listenTo()方法调用时,其第七个参数回调函数执行上下文总是当前目标object。*

“`

   var objA = {}, objB = {};

   _.extend(objA, Backbone.Events);

   _.extend(objB, Backbone.Events);

   objA.listenTo(objB, ‘test’, function(e) {

       console.log(‘listened it’);

   });

   //输出”listened it”

   objB.trigger(‘test’);

“`

### listenToOnce()

listenToOnce(obj, event,
callback)方法则能够兑现一个目的监听另一个目的上的轩然大波,并在该事件触发两遍后

### stopListening()

stopListening([other] [,event]
[,callback])方法使对象终止监听事件,若不带参数,则为止监听所有目的,移除所有已登记的回调函数;若第四个参数为空,则为止监听某目的上具备事件,移除为该对象注册的持有回调函数;若第多少个参数为空,甘休监听某目的上一定事件,移除为该事件注册的有着回调函数;参数均不为空,移除某目的上一定事件的指定回调函数:

“`

   var objA = {}, objB = {};

   _.extend(objA, Backbone.Events);

   _.extend(objB, Backbone.Events);

   objA.listenTo(objB, ‘test’, function(e) {

       console.log(‘listened it’);

   });

   //输出”listened it”

   objB.trigger(‘test’);

   objA.stopListening(objB);

   //不输出

   objB.trigger(‘test’);

“`

## 事件与视图

在Backbone中,事件选拔最多的光景总是与视图对象一起,在一个视图中,要监听事件,一般有三种格局:DOM事件和伊夫nt事件API。

– DOM事件

   添加DOM事件可以由此视图对象events属性或者jQuery.on()方法注册:

   – 使用events属性注册的轩然大波,回调函数的this指向视图对象

   – 使用jQuery注册事件,回调函数this指向DOM元素

– Event API

   使用伊夫nt API注册事件也有二种情况:

   –
使用on()方法注册事件,上下文默许是指向当前目的,也可以通过第七个参数传入作为回调函数上下文

   – 使用listenTo()注册事件,回调函数this指向当前目的

网站地图xml地图