thisの使い方
thisは一般的に関数内で使われ、関数の呼び出し方によって何を示すか変わってきます。
本ページでは、thisの使い方を説明します。
thisが何を示すのか?
thisは、呼び出し元のオブジェクトを示します。例えば、あるオブジェクトのメソッドとして呼び出した関数内で使うと、thisの中身はそのオブジェクトになります。
また、呼び出し元が異なるオブジェクトを指定することもあります。
つまり、呼び出し元や使い方によって、thisが何を示すのかは変わるということです。
thisには、以下のような使い方があります。
- グローバル実行コンテキストで実行する
- 関数コンテキストで実行する
- メソッドで呼び出す
- イベントハンドラーで呼び出す
- コンストラクタ関数で呼び出す
- callメソッドを使う
- applyメソッドを使う
- bindメソッドを使う
次からは、それぞれの使い方を説明します。
また、最後にthisを使うメリットについても説明しています。
グローバル実行コンテキストで呼び出す
グローバル実行コンテキストとは、関数の外側を意味します。
以下のように、thisをグローバル実行コンテキストで実行したとします。
var x = 1;
alert(this.x);
上記の例は、alert(x);と記述したのと同じで1が表示されます。
thisは、グローバル実行コンテキストではwindowオブジェクトを示します。このため、this.xはwindow.xです。windowオブジェクトは、ブラウザで表示した時に最初から存在し、グローバルオブジェクトと呼ばれます。
varで宣言したxは、windowオブジェクトのプロパティとして存在するグローバル変数です。したがって、グローバル変数xはwindow.xとも書けます。つまり、this.xとグローバル変数xは同じwindow.xです。
関数コンテキストで実行する
関数コンテキストとは、関数の内側を意味します。
以下のように、thisを関数コンテキストで実行したとします。
function func1() { alert(this.x); } var x = 1; func1();
上記は、グローバル実行コンテキストで実行した時と同じです。this.xはwindows.xと同じになります。ただし、これは非Strictモードで実行した時です。
以下のように、Sctictモード(厳格モード)で実行したとします。
function func1() { 'use strict'; alert(this.x); } var x = 1; func1();
'use strict'でSctictモードにしています。Strictモードは、非Strictモードではエラーにならないコードでも、悪影響を与える可能性がある場合はエラーにしたりします。
上記の場合、thisがundefinedとなり、エラーになります。これは、func1が直接呼び出されているためです。window.func1()で呼び出せば、this.xは1になります。
メソッドで呼び出す
オブジェクトのメソッドで呼び出した場合のthis利用例です。
const yamada = { address: "Tokyo", display: function() { alert("住所は" + this.address + "です。"); } }; yamada.display();
最後のyamada.display()で、displayがyamadaオブジェクトのメソッドとして呼び出されています。このため、thisはyamadaオブジェクトを示します。つまり、this.addressはyamada.addressを示すことになり、結果として「住所はTokyoです。」と表示されます。
グローバル実行コンテキストや直接関数を呼び出すとthisはwindowオブジェクトを示しましたが、この例のようにオブジェクトのメソッドとして呼び出すとthisはそのオブジェクトを示すようになります。
イベントハンドラーで呼び出す
イベントハンドラーで呼び出した場合のthis利用例です。
<p id="dom-test">これはテストです。</p> <script> function func1() { this.style.color = "red"; } const x = document.querySelector("#dom-test"); x.addEventListener("click", func1, false); </script>
最後のイベントリスナー(x.addEventListener)で、要素がクリックされるとイベントハンドラーのfunc1が呼び出されます。この時のthisは、id:dom-testの要素オブジェクトを示します。したがって、要素がクリックされると、クリックした要素の文字が赤に変わります。
コンストラクタ関数で呼び出す
コンストラクタ関数で呼び出した場合のthis利用例です。
function Peaple(address) {
this.address = address;
}
const yamada = new Peaple("Tokyo");
最後の行で、Peapleがyamadaオブジェクトのコンストラクタとして呼び出されています。この時、コンストラクタ関数内のthisは、yamadaオブジェクトを示します。したがって、this.addressは、yamada.addressプロパティを作成することになります。
なお、コンストラクタ関数については、オブジェクトの作り方をご参照ください。
callメソッドを使う
thisがオブジェクトを示すと言っても、以下はthis.addressがundefinedになります。
function display() { alert("住所は" + this.address + "です。"); } const yamada = { address: "Tokyo", }; display();
最後のdisplay()がオブジェクトのメソッドではなく、直接実行されています。このため、thisがwindowオブジェクトを示し、this.addressはaddress変数(window.address)と同じになります。address変数は宣言されていないため、undefinedになります。
もし、thisをyamadaオブジェクトにしたい場合は、callメソッドを使います。
function display() { alert("住所は" + this.address + "です。"); } const yamada = { address: "Tokyo", }; display.call(yamada);
callメソッドを使うと、thisで示すオブジェクトを指定できます。上記例では、thisがyamadaオブジェクトを示すことになるため、this.addressはTokyoになります。
callメソッドでは、引数も渡せます。
function display(x,y) { alert(x + this.address + y); } const yamada = { address: "Tokyo", }; display.call(yamada,"住所は","です。");
引数は、「住所は」と「です。」です。xとyで受け取っているため、結果として「住所はTokyoです。」と表示されます。
applyメソッドを使う
callメソッドの代わりに、applyメソッドを使うと、引数を配列で渡せます。
function display(x,y) { alert(x + this.address + y); } const yamada = { address: "Tokyo", }; const z = ["住所は","です。"]; display.apply(yamada,z);
最後の行(display.apply)で配列で引数を渡し、xとyで受け取っています。結果として、「住所はTokyoです。」と表示されます。
引数の数は、関数の使い方で説明した残余引数やargumentsを利用して、可変にすることもできます。
bindメソッドを使う
以下のスクリプトがあったとします。
const z = { x: 20, display: function() { alert(this.x); } }; var x = 10; const y = z.display; y();
最後のy()は、直接実行されているためthisがwindowを示し、this.xは変数xとなります。つまり、オブジェクトzのプロパティxは20ですが、結果としてwindow.xを示すことになって10が表示されます。
もし、this.xをオブジェクトzのプロパティxにしたい場合は、bindメソッドが使えます。
const z = {
x: 20,
display: function() {
alert(this.x);
}
};
var x = 10;
const y = z.display.bind(z);
y();
変えたのは、bind(z)部分だけです。これで、thisがzオブジェクトを示すようになり、this.xはz.xと同じになります。つまり、結果として20が表示されます。
thisを使うメリット
thisのメリットは、1つのthisで複数のオブジェクトを扱えることです。イベントハンドラーで呼び出すで説明した使い方を、複数の要素オブジェクトに対して使ってみます。
<p id="dom-test1">これはテストです。</p> <p id="dom-test2">これはテストです。</p> <script> function func1() { this.style.color = "red"; } const x = document.querySelector("#dom-test1"); const y = document.querySelector("#dom-test2"); x.addEventListener("click", func1, false); y.addEventListener("click", func1, false); </script>
赤字から呼び出した時はthisがdom-test1の要素オブジェクト、青字から呼び出した時はthisがdom-test2の要素オブジェクトを示すため、それぞれの要素オブジェクトをクリックすると赤に変わります。つまり、不特定多数のオブジェクトから呼び出されても、1つの記述(この例ではfunc1という1つの関数だけ)で各オブジェクトに対して操作が可能です。
もう1つの例です。
function Peaple(address) {
this.address = address;
}
const yamada = new Peaple("Tokyo");
const suzuki = new Peaple("Kyoto");
yamadaでもsuzukiでもコンストラクタを呼び出すと、thisはそれぞれのオブジェクトを示すため、1つのコンストラクタで複数のインスタンスが作成できます。