JavaScriptでコールバック関数を使うことがよくある。
コールバック関数の中で、コールバック関数の外側の値を参照したいこともよくある。
参照する「コールバック関数の外側の値」にはいくつかのパターンがある。
どうコードを書けばどの値を参照できるかすぐ忘れるので、メモしておく。
- コールバックが定義された時点の値を参照する
- クロージャを使って値を保存しておく
- コールバックが呼ばれた時点での、コールバックが定義された箇所の値を参照する
- シンプルに変数を参照するだけ
- コールバックが呼ばれた時点での、イベントが発生した箇所の値を参照する
- イベントの発生源で値を渡す(他に方法あるのかな…)
テストコード
node.jsでやる。
Events
ブラウザでやるなら、addEventLister/dispatchEventとか使うのがいいと思う。
Creating custom events
例 1
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
(()=>{
// 「コールバックが定義された時点の値」
var x = 'function-define-1';
// 1. コールバックが定義された時点の値を参照する
myEmitter.on('event-closure', (() => {
var inner_x = x;
return () => {
console.log('closure-x: ' + inner_x);
};
})());
// 2. コールバックが呼ばれた時点での、コールバックが定義された箇所の値を参照する
myEmitter.on('event-arrowfunction', () => {
console.log('arrowfunction-x: ' + x);
});
// 3. コールバックが呼ばれた時点での、イベントが発生した箇所の値を参照する
myEmitter.on('event-arrowfunction-args', (x) => {
console.log('arrowfunction-args-x: ' + x);
});
// 「コールバックが呼ばれた時点での、コールバックが定義された箇所の値」
var x = 'function-define-2';
})();
(()=>{
// 「コールバックが呼ばれた時点での、イベントが発生した箇所の値」
var x = 'function-call';
// イベントを発生させる。
myEmitter.emit('event-closure');
myEmitter.emit('event-arrowfunction');
myEmitter.emit('event-arrowfunction-args', x);
})();
実行結果。
closure-x: function-define-1
arrowfunction-x: function-define-2
arrowfunction-args-x: function-call
例 2
もうちょっと実践的?な例は下記。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
(()=>{
for(var i=0; i<2; i++){
// 1. コールバックが定義された時点の値を参照する
myEmitter.on('event-closure-'+i, (() => {
var inner_i = i;
return () => console.log('event-closure-i: ' + inner_i);
})());
// 2. コールバックが呼ばれた時点での、コールバックが定義された箇所の値を参照する
myEmitter.on('event-arrowfunction-'+i, () => {
console.log('event-arrowfunction-i: ' + i);
});
}
})();
(()=>{
for(var i=0; i<2; i++){
console.log('i: ' + i);
myEmitter.emit('event-closure-'+i);
myEmitter.emit('event-arrowfunction-'+i);
}
})();
実行結果。
i: 0
event-closure-i: 0
event-arrowfunction-i: 2
i: 1
event-closure-i: 1
event-arrowfunction-i: 2