EvEmitter
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ この記事で書いてたちょっと高機能版EventEmitterです
この記事書いてるときに せっかくだからとちょっと高機能(自分が使いやすい方向に)に進化させてみたものです
本家と使い方も多少違いますし 同じ名前ってややこしいよね ということでちょっと略して
EvEmitter
(イヴミッター)
と 名づけています
リスナの登録です
イベントが起きた時に指定した回数だけ関数が実行されます
on(イベントの名前, 実行する関数)
回数は省略すると 無制限になります
addEventListener(イベントの名前, 実行する関数)
onと一緒
だけど 回数指定はできないです
once(イベントの名前, 実行する関数)
onの回数が一回にした固定版
off()
登録されたリスナを削除します
すでにあるEventEmitterではリスナ削除が使いづらかった覚えがあるので使いやすく作ってます(自分的に)
引数なしはすべてを選択した扱いで 全て削除になります
off(イベントの名前)
一致したイベントの名前のリスナを全て削除します
off(null, 実行する関数)
一致した実行する関数のリスナを全て削除します
off(イベントの名前, 実行する関数)
一致したイベントの名前のリスナの中から 実行する関数が一致したものを削除します
removeEventListener
offと一緒です
offOnly()
offと逆で 指定されたリスナだけ残します
引数なしはすべてを選択した扱いなので 全てが残るので無意味です
offOnly(イベントの名前)
一致したイベントの名前のリスナだけを残して削除します
offOnly(null, 実行する関数)
一致した実行する関数のリスナだけ残して削除します
offOnly(イベントの名前, 実行する関数)
一致したイベントの名前のリスナの中から 実行する関数が一致したものだけを残して削除します
emit(イベントの名前, リスナ関数への引数, ...)
2つめ以降の引数をリスナ関数に渡して実行します
複数リスナがあると登録順に実行します
リスナの関数の返り値がfalseだった場合は それ以降は行いません
dispatchEvent
fire
emitと一緒です
emitAll(イベントの名前, リスナ関数への引数, ...)
emitの途中でやめない版です
dispatchEventAll
fireAll
emitAllと一緒です
あまり同時にいくつも登録したりイベント起こしたりするものじゃないし いいかなっと
offOnly だけは イベント "a" と"b" と "c" だけ残して削除ってできないので使いにくい時もありますけど まずそれだけ残すなんてめったに使わなそうなので複数指定機能は入れてないままです
一時的にはずす
これもoffしてonすればいいかなと思って作ろうとしてやめました
でも イベント時の関数を定義したスコープ以外だと offした後にonできないとか 同じイベント名がいっぱいあると順番変わるとか 問題もあるのでもし拡張する時がくれば入れたほうがいいのかも
メソッドチェーンできます
emitでは リスナ関数の返り値がfalseになったところで終わります
offでは 指定のものを offOnly では指定のもの以外を削除します
off は引数によって 指定のイベント名のリスナ全部削除や指定の関数を実行するリスナを全削除もできます
offOnlyは逆に指定したのだけ残します
本家と使い方も多少違いますし 同じ名前ってややこしいよね ということでちょっと略して
EvEmitter
(イヴミッター)
と 名づけています
EvEmitter
function EvEmitter(){
this.listeners = {}
}
EvEmitter.prototype.on = function(evname, n, evaction){
if(typeof n === "function"){
evaction = n
n = 0
}
if(typeof evaction !== "function"){
return
}
var evs = this.listeners[evname] || []
n = ~~n
if(n>0){
var that = this
evs.push(function wrapped_evaction(/*evargs*/){
evaction.apply(null, arguments)
--n === 0 && that.off(evname, wrapped_evaction)
})
}else{
evs.push(evaction)
}
this.listeners[evname] = evs
return this
}
EvEmitter.prototype.addEventListener = function(evname, evaction){
return this.on(evname, 0, evaction)
}
EvEmitter.prototype.once = function(evname, evaction){
return this.on(evname, 1, evaction)
}
EvEmitter.prototype.off = function(evname, evaction){
for(var key in this.listeners){
if(evname && evname !== key){
continue
}
if(!evaction){
this.listeners[key] = []
continue
}
this.listeners[key] = this.listeners[key].filter(function(e){
return e !== evaction
})
}
return this
}
EvEmitter.prototype.removeEventListener = EvEmitter.prototype.off
EvEmitter.prototype.offOnly = function(evname, evaction){
for(var key in this.listeners){
if(evname && evname !== key){
this.listeners[key] = []
continue
}
if(!evaction){
continue
}
this.listeners[key] = this.listeners[key].filter(function(e){
return e === evaction
})
}
return this
}
EvEmitter.prototype.emit = function(evname /*, evargs */){
var args = [].slice.call(arguments, 1)
this.listeners[evname] && this.listeners[evname].some(function(evaction){
return false === evaction.apply(null, args)
})
return this
}
EvEmitter.prototype.fire = EvEmitter.prototype.dispatchEvent = EvEmitter.prototype.emit
EvEmitter.prototype.emitAll = function(evname /*, evargs */){
var args = [].slice.call(arguments, 1)
this.listeners[evname] && this.listeners[evname].forEach(function(evaction){
evaction.apply(null, args)
})
return this
}
EvEmitter.prototype.fireAll = EvEmitter.prototype.dispatchEventAll = EvEmitter.prototype.emitAll
this.listeners = {}
}
EvEmitter.prototype.on = function(evname, n, evaction){
if(typeof n === "function"){
evaction = n
n = 0
}
if(typeof evaction !== "function"){
return
}
var evs = this.listeners[evname] || []
n = ~~n
if(n>0){
var that = this
evs.push(function wrapped_evaction(/*evargs*/){
evaction.apply(null, arguments)
--n === 0 && that.off(evname, wrapped_evaction)
})
}else{
evs.push(evaction)
}
this.listeners[evname] = evs
return this
}
EvEmitter.prototype.addEventListener = function(evname, evaction){
return this.on(evname, 0, evaction)
}
EvEmitter.prototype.once = function(evname, evaction){
return this.on(evname, 1, evaction)
}
EvEmitter.prototype.off = function(evname, evaction){
for(var key in this.listeners){
if(evname && evname !== key){
continue
}
if(!evaction){
this.listeners[key] = []
continue
}
this.listeners[key] = this.listeners[key].filter(function(e){
return e !== evaction
})
}
return this
}
EvEmitter.prototype.removeEventListener = EvEmitter.prototype.off
EvEmitter.prototype.offOnly = function(evname, evaction){
for(var key in this.listeners){
if(evname && evname !== key){
this.listeners[key] = []
continue
}
if(!evaction){
continue
}
this.listeners[key] = this.listeners[key].filter(function(e){
return e === evaction
})
}
return this
}
EvEmitter.prototype.emit = function(evname /*, evargs */){
var args = [].slice.call(arguments, 1)
this.listeners[evname] && this.listeners[evname].some(function(evaction){
return false === evaction.apply(null, args)
})
return this
}
EvEmitter.prototype.fire = EvEmitter.prototype.dispatchEvent = EvEmitter.prototype.emit
EvEmitter.prototype.emitAll = function(evname /*, evargs */){
var args = [].slice.call(arguments, 1)
this.listeners[evname] && this.listeners[evname].forEach(function(evaction){
evaction.apply(null, args)
})
return this
}
EvEmitter.prototype.fireAll = EvEmitter.prototype.dispatchEventAll = EvEmitter.prototype.emitAll
メソッド一覧
on(イベントの名前, 実行できる回数, 実行する関数)リスナの登録です
イベントが起きた時に指定した回数だけ関数が実行されます
on(イベントの名前, 実行する関数)
回数は省略すると 無制限になります
addEventListener(イベントの名前, 実行する関数)
onと一緒
だけど 回数指定はできないです
once(イベントの名前, 実行する関数)
onの回数が一回にした固定版
off()
登録されたリスナを削除します
すでにあるEventEmitterではリスナ削除が使いづらかった覚えがあるので使いやすく作ってます(自分的に)
引数なしはすべてを選択した扱いで 全て削除になります
off(イベントの名前)
一致したイベントの名前のリスナを全て削除します
off(null, 実行する関数)
一致した実行する関数のリスナを全て削除します
off(イベントの名前, 実行する関数)
一致したイベントの名前のリスナの中から 実行する関数が一致したものを削除します
removeEventListener
offと一緒です
offOnly()
offと逆で 指定されたリスナだけ残します
引数なしはすべてを選択した扱いなので 全てが残るので無意味です
offOnly(イベントの名前)
一致したイベントの名前のリスナだけを残して削除します
offOnly(null, 実行する関数)
一致した実行する関数のリスナだけ残して削除します
offOnly(イベントの名前, 実行する関数)
一致したイベントの名前のリスナの中から 実行する関数が一致したものだけを残して削除します
emit(イベントの名前, リスナ関数への引数, ...)
2つめ以降の引数をリスナ関数に渡して実行します
複数リスナがあると登録順に実行します
リスナの関数の返り値がfalseだった場合は それ以降は行いません
dispatchEvent
fire
emitと一緒です
emitAll(イベントの名前, リスナ関数への引数, ...)
emitの途中でやめない版です
dispatchEventAll
fireAll
emitAllと一緒です
できないこと
複数同時に 登録・削除・それだけ残す・イベントを起こすあまり同時にいくつも登録したりイベント起こしたりするものじゃないし いいかなっと
offOnly だけは イベント "a" と"b" と "c" だけ残して削除ってできないので使いにくい時もありますけど まずそれだけ残すなんてめったに使わなそうなので複数指定機能は入れてないままです
一時的にはずす
これもoffしてonすればいいかなと思って作ろうとしてやめました
でも イベント時の関数を定義したスコープ以外だと offした後にonできないとか 同じイベント名がいっぱいあると順番変わるとか 問題もあるのでもし拡張する時がくれば入れたほうがいいのかも
使い方
onは第二引数に数値が入るとその回数だけ実行できるリスナを登録しますメソッドチェーンできます
emitでは リスナ関数の返り値がfalseになったところで終わります
var e = new EvEmitter
e.on("on1", function(a,b){console.log("on1", a,b)})
e.on("on1", function(a){console.log("on1-2", a)})
e.emit("on1")
e.emit("on1", 1,2,3,4)
console.log("====")
e.on("on2", 1, function(a,b){console.log("on2", a,b)})
e.emit("on2", 10, 11)
e.emit("on2", 20, 21)
console.log("====")
e.on("on3", 0, function(a){console.log("on3", a)})
e.emit("on3", 3)
e.emit("on3", 3)
e.emit("on3", 3)
console.log("====")
e.on("on4", 5, function(a,b){console.log("on4", a,b)})
e.emit("on4", 4,44,444)
e.emit("on4", 4,44,444)
e.emit("on4", 4,44,444)
e.emit("on4", 4,44,444)
e.emit("on4", 4,44,444)
e.emit("on4", 999,999)
console.log("====")
e.on("on5", function(a){
console.log("on5-1", a)
return false
}).on("on5", function(a){
console.log("on5-2", a)
}).emit("on5", "std").emitAll("on5", "all")
e.on("on1", function(a,b){console.log("on1", a,b)})
e.on("on1", function(a){console.log("on1-2", a)})
e.emit("on1")
e.emit("on1", 1,2,3,4)
console.log("====")
e.on("on2", 1, function(a,b){console.log("on2", a,b)})
e.emit("on2", 10, 11)
e.emit("on2", 20, 21)
console.log("====")
e.on("on3", 0, function(a){console.log("on3", a)})
e.emit("on3", 3)
e.emit("on3", 3)
e.emit("on3", 3)
console.log("====")
e.on("on4", 5, function(a,b){console.log("on4", a,b)})
e.emit("on4", 4,44,444)
e.emit("on4", 4,44,444)
e.emit("on4", 4,44,444)
e.emit("on4", 4,44,444)
e.emit("on4", 4,44,444)
e.emit("on4", 999,999)
console.log("====")
e.on("on5", function(a){
console.log("on5-1", a)
return false
}).on("on5", function(a){
console.log("on5-2", a)
}).emit("on5", "std").emitAll("on5", "all")
on1 undefined undefined
on1-2 undefined
on1 1 2
on1-2 1
====
on2 10 11
====
on3 3
on3 3
on3 3
====
on4 4 44
on4 4 44
on4 4 44
on4 4 44
on4 4 44
====
on5-1 std
on5-1 all
on5-2 all
on1-2 undefined
on1 1 2
on1-2 1
====
on2 10 11
====
on3 3
on3 3
on3 3
====
on4 4 44
on4 4 44
on4 4 44
on4 4 44
on4 4 44
====
on5-1 std
on5-1 all
on5-2 all
offでは 指定のものを offOnly では指定のもの以外を削除します
var ee = new EvEmitter
var fn = function(a){console.log(a)}
ee
.on("a", fn)
.on("b", fn)
.on("c", fn)
.emit("a", "a")
.emit("b", "b")
.emit("c", "c")
console.log("--")
ee
.off("a")
.emit("a", "a")
.emit("b", "b")
.emit("c", "c")
console.log("====")
var ee2 = new EvEmitter
ee2
.on("a", fn)
.on("b", fn)
.on("c", fn)
.emit("a", "a")
.emit("b", "b")
.emit("c", "c")
console.log("--")
ee2
.offOnly("a")
.emit("a", "a")
.emit("b", "b")
.emit("c", "c")
var fn = function(a){console.log(a)}
ee
.on("a", fn)
.on("b", fn)
.on("c", fn)
.emit("a", "a")
.emit("b", "b")
.emit("c", "c")
console.log("--")
ee
.off("a")
.emit("a", "a")
.emit("b", "b")
.emit("c", "c")
console.log("====")
var ee2 = new EvEmitter
ee2
.on("a", fn)
.on("b", fn)
.on("c", fn)
.emit("a", "a")
.emit("b", "b")
.emit("c", "c")
console.log("--")
ee2
.offOnly("a")
.emit("a", "a")
.emit("b", "b")
.emit("c", "c")
a
b
c
--
b
c
====
a
b
c
--
a
b
c
--
b
c
====
a
b
c
--
a
off は引数によって 指定のイベント名のリスナ全部削除や指定の関数を実行するリスナを全削除もできます
var ee
var fn1 = function(a){console.log(1,a)}
var fn2 = function(a){console.log(2,a)}
ee = new EvEmitter
ee
.on("a", fn1)
.on("b", fn2)
.off("a")
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("b", fn2)
.off(null, fn2)
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("a", fn2)
.on("b", fn2)
.on("b", fn1)
.off("a", fn2)
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("a", fn2)
.on("b", fn2)
.on("b", fn1)
.off()
.emit("a", "a")
.emit("b", "b")
var fn1 = function(a){console.log(1,a)}
var fn2 = function(a){console.log(2,a)}
ee = new EvEmitter
ee
.on("a", fn1)
.on("b", fn2)
.off("a")
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("b", fn2)
.off(null, fn2)
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("a", fn2)
.on("b", fn2)
.on("b", fn1)
.off("a", fn2)
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("a", fn2)
.on("b", fn2)
.on("b", fn1)
.off()
.emit("a", "a")
.emit("b", "b")
2 "b"
====
1 "a"
====
1 "a"
2 "b"
1 "b"
====
====
1 "a"
====
1 "a"
2 "b"
1 "b"
====
offOnlyは逆に指定したのだけ残します
var ee
var fn1 = function(a){console.log(1,a)}
var fn2 = function(a){console.log(2,a)}
ee = new EvEmitter
ee
.on("a", fn1)
.on("b", fn2)
.offOnly("a")
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("b", fn2)
.offOnly(null, fn2)
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("a", fn2)
.on("b", fn2)
.on("b", fn1)
.offOnly("a", fn2)
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("a", fn2)
.on("b", fn2)
.on("b", fn1)
.offOnly()
.emit("a", "a")
.emit("b", "b")
var fn1 = function(a){console.log(1,a)}
var fn2 = function(a){console.log(2,a)}
ee = new EvEmitter
ee
.on("a", fn1)
.on("b", fn2)
.offOnly("a")
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("b", fn2)
.offOnly(null, fn2)
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("a", fn2)
.on("b", fn2)
.on("b", fn1)
.offOnly("a", fn2)
.emit("a", "a")
.emit("b", "b")
console.log("====")
ee = new EvEmitter
ee
.on("a", fn1)
.on("a", fn2)
.on("b", fn2)
.on("b", fn1)
.offOnly()
.emit("a", "a")
.emit("b", "b")
1 "a"
====
2 "b"
====
2 "a"
====
1 "a"
2 "a"
2 "b"
1 "b"
====
2 "b"
====
2 "a"
====
1 "a"
2 "a"
2 "b"
1 "b"