快捷搜索:
来自 新京葡娱乐场网址 2019-07-30 01:33 的文章
当前位置: 67677新澳门手机版 > 新京葡娱乐场网址 > 正文

自定义事件,js观察者模式学习总结

探究 JavaScript 的观望者方式(自定义事件)

2016/08/25 · JavaScript · 观察者方式, 设计情势

正文笔者: 伯乐在线 - winty 。未经小编许可,禁止转发!
招待到场伯乐在线 专辑作者。

萧萧,前不久到位了三个笔试,里面有一到JS编制程序题,当时瞧着难点就蒙圈。后来商讨了一晃,原本就是所谓的观望者格局。就记下来 ^_^

题目

JavaScript

[附加题] 请完毕下边包车型地铁自定义事件 伊夫nt 对象的接口,功效见注释(测验1) 该 Event 对象的接口必要能被别的对象开始展览复用(测量检验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, 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) { //你的代码 } };

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方法。在那之中第一个参数便是事件类型,第4个参数便是要传进函数的参数。

是还是不是那么些回事呢?很好,那么大家要写的代码正是:

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

以此是ES6的新对象方法,用于对象的会面,将源对象(source)的具备可枚举属性,复制到目标对象(target)。

情趣是将伊芙nt里面包车型大巴可枚举的指标和办法放到person1里面。

图片 2

也正是说,假若源对象某些属性的值是指标,那么指标对象拷贝获得的是以此目的的援用。由于开始展览测量试验一的时候调用了on方法,所以event里面已经有了handles这一个可枚举的质量。然后再各自合併到多个person里面包车型地铁话,五个person对象里面的handles都只是一个引用。所以就互相影响了。

如果assign方法要兑现深克隆则要如此:

图片 3

难题是,标题已经固化了章程,我们无法改改那么些点子。

因而,大家无法不将handles这几个特性定义为恒河沙数的,然后在person调用on方法的时候再分别发出handles这几个目的。

约等于说精确的做法应该是:

JavaScript

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

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 在八个事变之中只可以登记拾个事件
</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>

本文由67677新澳门手机版发布于新京葡娱乐场网址,转载请注明出处:自定义事件,js观察者模式学习总结

关键词: