>

的观察者模式,js观察者模式学习总结

- 编辑:至尊游戏网站 -

的观察者模式,js观察者模式学习总结

座谈 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 () { 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 伊芙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, 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)。

意思是将Event里面的可枚举的对象和办法放到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>

实现它的效劳

挂号与揭橥
<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>

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观察者模式学习总结