澳门在线威尼斯官方 > 威尼斯澳门在线 > 自定义事件,js观察者模式学习总结

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

浏览次数:150 时间:2019-12-12

有关小编:winty

威尼斯澳门在线 1

前端程序员,前端发烧友。博客: 个人主页 · 小编的作品 · 1 ·  

威尼斯澳门在线 2

兑现它的效果

注册与揭橥
<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>

座谈 JavaScript 的观望者方式(自定义事件)

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

正文笔者: 伯乐在线 - winty 。未经小编许可,禁绝转发!
招待加入伯乐在线 专栏撰稿者。

萧萧,明天在场了三个笔试,里面有生龙活虎到JS编制程序题,那个时候看着主题材料就蒙圈。后来切磋了须臾间,原来正是所谓的观看者情势。就记下来 ^_^

题目

JavaScript

[附加题] 请达成上边包车型大巴自定义事件 Event 对象的接口,作用见注释(测量试验1卡塔尔(قطر‎ 该 Event 对象的接口要求能被别的对象进行复用(测量试验2卡塔尔(قطر‎ // 测验1 Event.on('test', function (result卡塔尔(قطر‎ { console.log(result卡塔尔国; }卡塔尔; 伊芙nt.on('test', function (卡塔尔(英语:State of Qatar) { 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'卡塔尔国; }卡塔尔(英语:State of Qatar); person2.on('call2', function (卡塔尔国 { console.log('person2'卡塔尔; }卡塔尔(英语:State of Qatar); person1.emit('call1'卡塔尔(英语:State of Qatar); // 输出 '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方法。在那之中第二个参数正是事件类型,第一个参数正是要传进函数的参数。

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

JavaScript

var Event = { // 通过on接口监听事件eventName // 假若事件eventName被触发,则实行callback回调函数 on: function (eventName, callback卡塔尔(英语:State of Qatar) { //小编的代码 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'卡塔尔(英语:State of Qatar); }卡塔尔国; 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之间是互相独立的。

直白测验,开掘输出了

威尼斯澳门在线 3

本条看似是难点必要某些出入呢,恐怕那才是主题材料的坑吧!

解释一下,Object.assign(person1, Event卡塔尔国;

以此是ES6的新对象方法,用于对象的统后生可畏,将源对象(source)的持有可枚举属性,复制到指标对象(target)。

意思是将Event里面包车型客车可枚举的对象和方法放到person1里面。

威尼斯澳门在线 4

也正是说,若是源对象有个别属性的值是指标,那么目的对象拷贝得到的是其一指标的援引。由于开展测量检验黄金时代的时候调用了on方法,所以event里面早就有了handles这些可枚举的品质。然后再各自合并到多个person里面包车型地铁话,三个person对象里面包车型大巴handles都只是二个征引。所以就竞相影响了。

假使assign方法要兑现深克隆则要这么:

威尼斯澳门在线 5

主题素材是,标题已经定位了法子,大家不能改改那几个主意。

由此,咱们亟须将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卡塔尔(英语:State of Qatar) { //你的代码 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]);
           }
       }
    }
};

经过那道题,以为考得真的很抢眼何况很考基本功。好啊。笔者恐怕可以复习去了。

打赏协助我写出更加多好小说,感激!

打赏小编

金镶玉裹福禄双全它的成效

登记与揭橥
<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>

打赏扶持自身写出越多好作品,谢谢!

任选后生可畏种支付方式

威尼斯澳门在线 6 威尼斯澳门在线 7

1 赞 5 收藏 评论

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>

计算,写东西真累,今后会习于旧贯的。。。

本文由澳门在线威尼斯官方发布于威尼斯澳门在线,转载请注明出处:自定义事件,js观察者模式学习总结

关键词:

上一篇:异步JavaScript的发展历程

下一篇:没有了