この記事で書いてたちょっと高機能版EventEmitterです

この記事書いてるときに せっかくだからとちょっと高機能(自分が使いやすい方向に)に進化させてみたものです

本家と使い方も多少違いますし 同じ名前ってややこしいよね ということでちょっと略して

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


メソッド一覧

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

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")
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")
2 "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")
1 "a"
====
2 "b"
====
2 "a"
====
1 "a"
2 "a"
2 "b"
1 "b"