的旁观者格局,js观察者情势学习计算

作者: 前端知识  发布:2019-07-26

冲突 JavaScript 的观看者格局(自定义事件)

2016/08/25 · JavaScript · 观看者情势, 设计模式

本文作者: 伯乐在线 - winty 。未经小编许可,禁止转发!
招待到场伯乐在线 专栏撰稿人。

萧萧,前不久在场了二个笔试,里面有一到JS编制程序题,当时望着主题素材就蒙圈。后来探讨了刹那间,原本便是所谓的观望者形式。就记下来 ^_^

题目

JavaScript

[附加题] 请达成下边包车型地铁自定义事件 伊芙nt 对象的接口,效用见注释(测量检验1) 该 伊夫nt 对象的接口供给能被别的对象进行复用(测量试验2) // 测量试验1 伊夫nt.on('test', function (result) { console.log(result); }); Event.on('test', function () { console.log('test'); }); 伊夫nt.emit('test', 'hello world'); // 输出 'hello world' 和 'test' // 测验2 var person1 = {}; var person2 = {}; Object.assign(person1, Event); 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 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]); } } } };

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, 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'

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, 伊夫nt);

本条是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 在多个平地风波之中只可以登记12个事件
</p>

打赏扶助自个儿写出越来越多好小说,多谢!

任选一种支付格局

金沙澳门官网网址 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(){
console.log('披发及腰')
})
girl.on('长长的头发及腰',function(){
console.log('长长的头发及腰2')
})
girl.emit('长头发及腰')
</code>

关于小编:winty

金沙澳门官网网址 6

前端程序猿,前端爱好者。博客: 个人主页 · 笔者的小说 · 1 ·  

金沙澳门官网网址 7

相传是Ali面试题 完成效果与利益

<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>

本文由金沙澳门官网发布于前端知识,转载请注明出处:的旁观者格局,js观察者情势学习计算

关键词: 金沙澳门官网