JavaScriptのthis参照について
Follow @venividivici830
JavaScriptのthisは、関数の呼ばれ方によって、参照するオブジェクトが異なる。ただし、アロー関数はこの限りではない。
main.js
test()のように普通の関数として呼んだ時は、グローバル変数globalと等しい。obj.test()のようにメソッド呼び出しした時は、レシーバーオブジェクトobj(.の左辺のオブジェクト)と等しい。bindで明示的にthisが参照するオブジェクトを指定した時は、指定したオブジェクト(上の例ではobj2)と等しい。なお、(test.bind(obj2))();は、test.call(obj2);、test.apply(obj2);などとしても同じ。
main.js
この動作は、クライアントサイド、サーバーサイドともに共通である。
ボタンを押すと、コンソールに下記が出力
ƒ HTMLButtonElement() { [native code] }
HTMLButtonElementは、querySelectorとかの戻り値と同じクラス。
補足だが、継承構造は下記。
https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement
下記では、人を表現するPersonクラスを定義した。Personクラスのクラスメソッドであるaddにより、新しい人が作成され、人のリスト_personsに追加される。新しい人が追加されると、addという名前のイベントが発行される。Observerオブジェクトは、addイベントを監視するオブザーバーである。addイベントが通知されると、Observer.handleAddメソッドが呼び出される。Person.addListenerメソッドにより、オブザーバーとして登録される。
main.js
上記コードを実行すると、thisがイベントソースであるEventEmitterを参照していることがわかる。
thisにObserver自身を参照させるには、下記のようにbindを使う。
thisがObserverオブジェクトを参照するようになった。
JavaScriptのthisは、関数の呼ばれ方によって、参照するオブジェクトが異なる。ただし、アロー関数はこの限りではない。
普通の関数として呼ばれた場合、メソッドとして呼ばれた場合、明示的に指定した場合
main.js
function test() {
console.log('this === global');
console.log(this === global);
console.log('this === obj');
console.log(this === obj);
console.log('this === obj2');
console.log(this === obj2);
console.log('');
}
var obj = {
test: test
};
var obj2 = {}
console.log('***** test() *****');
test();
console.log('***** obj.test() *****');
obj.test();
console.log('***** (test.bind(obj2))() *****');
(test.bind(obj2))();
$ node main.js
***** test() *****
this === global
true
this === obj
false
this === obj2
false
***** obj.test() *****
this === global
false
this === obj
true
this === obj2
false
***** (test.bind(obj2))() *****
this === global
false
this === obj
false
this === obj2
true
test()のように普通の関数として呼んだ時は、グローバル変数globalと等しい。obj.test()のようにメソッド呼び出しした時は、レシーバーオブジェクトobj(.の左辺のオブジェクト)と等しい。bindで明示的にthisが参照するオブジェクトを指定した時は、指定したオブジェクト(上の例ではobj2)と等しい。なお、(test.bind(obj2))();は、test.call(obj2);、test.apply(obj2);などとしても同じ。
コンストラクターとして呼ばれた場合
生成されたインスタンスを参照。main.js
var obj = null;
function Constructor() {
obj = this;
}
var instance = new Constructor();
console.log(obj === instance);
$ node main.js
true
イベントハンドラー/リスナーとして呼ばれた場合
イベントハンドラー/リスナー内では、thisはイベントソースオブジェクト(イベントの発行元オブジェクト)を参照する。この動作は、クライアントサイド、サーバーサイドともに共通である。
クライアントサイドの場合
クライアントサイドでは、イベントハンドラー/リスナー内のthisは、設定先の要素自身を参照する。
<button id="test"></button>
(function() {
document.addEventListener('DOMContentLoaded', function() {
var button = document.querySelector('#test');
button.addEventListener('click', function() {
console.log(this.constructor)
});
})
})();
ボタンを押すと、コンソールに下記が出力
ƒ HTMLButtonElement() { [native code] }
HTMLButtonElementは、querySelectorとかの戻り値と同じクラス。
補足だが、継承構造は下記。
https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement
Nodeの場合
下記に例を示す。下記では、人を表現するPersonクラスを定義した。Personクラスのクラスメソッドであるaddにより、新しい人が作成され、人のリスト_personsに追加される。新しい人が追加されると、addという名前のイベントが発行される。Observerオブジェクトは、addイベントを監視するオブザーバーである。addイベントが通知されると、Observer.handleAddメソッドが呼び出される。Person.addListenerメソッドにより、オブザーバーとして登録される。
main.js
const events = require('events');
const EventEmitter = events.EventEmitter;
class Person {
constructor(name) {
this._name = name;
}
}
// クラス変数
Person._persons = [];
Person._eventEmitter = new EventEmitter();
// クラスメソッド
Person.add = function(name) {
var person = new this(name);
this._persons.push(person);
this._eventEmitter.emit('add');
}
Person.addListener = function(event, listener) {
this._eventEmitter.on(event, listener);
}
// オブザーバー
const Observer = {
handleAdd: function() {
console.debug(this)
}
}
// イベントハンドラーの登録
Person.addListener('add', Observer.handleAdd)
Person.add('John');
上記コードを実行すると、thisがイベントソースであるEventEmitterを参照していることがわかる。
$ node main.js
EventEmitter {
_events: { add: [Function: handleAdd] },
_eventsCount: 1,
_maxListeners: undefined }
thisにObserver自身を参照させるには、下記のようにbindを使う。
// イベントハンドラーの登録
// Person.addListener('add', Observer.handleAdd)
Person.addListener('add', Observer.handleAdd.bind(Observer))
$ node main.js
{ handleAdd: [Function: handleAdd] }
thisがObserverオブジェクトを参照するようになった。
コメント
コメントを投稿