JavaScriptをしっかり勉強 vol.2 this

プログラム
date 2014.05.06 tag JavaScript

かなり時間が空いてしまいましたがJavaScriptの勉強したことを書いていくエントリーvol.2です。今回は「this」についてのエントリーです!thisはプログラムの記述を便利にしてくれる反面、混乱しやすいものですね。

thisが参照するもの

「this」は特定のオブジェクトへの参照を指すもので、context(文脈)によって決まるものです。thisが参照するパターンは基本的に次のものになり、適切に使用できればコードの簡略化ができます。ただし、newをする際のthisは違う挙動となります。(※これは次回以降のエントリーにて記載予定)

  • グルーバル領域のthisはグローバルオブジェクトであるwindowオブジェクトを参照
  • 関数呼び出しの中で使われるthisもwindowオブジェクトを参照
  • メソッド呼び出しの中で使われるthisはそれが格納されているオブジェクトを参照
  • イベントハンドラ内で使われるthisはイベントハンドラを設定した要素自身を参照 ※クライアントサイド(ブラウザ実行)
JSthisの挙動確認コード

JavaScriptなのでグローバルオブジェクトはwindowオブジェクトです。

ちなみにメソッド呼び出しの場合、呼び出しているオブジェクトのことを「レシーバオブジェクト」と呼びます。「test_obj.func()」という記述の場合は「test_obj」というのがレシーバオブジェクトです。

ある時点のthisを別のところで使うには

thisはcontextによって変化していきます。

例えばボタンクリックイベントで走らせたAjaxのコールバック関数内のthisはcontetが変化しているので、clickイベントハンドラを設定した要素を参照できません。Ajax成功後のコールバック関数のthisの値はさきほどのルールに従って「xhr」(XMLHttpRequestオブジェクト)を参照することになります。

でもせっかくclickした要素をthisとして扱ったのだから、Ajaxのコールバック関数でもそれとして扱いたいということがあります。

このケースはある種のテクニックとしてカバーすることが可能です。コールバック関数の中ではthisが参照するオブジェクトは変化しますが、イベントハンドラ内でthisを別の変数に代入しておくことでコールバック関数の内部でもその変数を参照できます。これはJavaScriptの言語使用で、親の関数スコープを子の関数スコープを参照できることに基づいています。(下図参照)

js_function_scope
JSAjaxのコールバック関数の中でクリックしたthisを扱いたい

この例ではボタンクリック時のthisが参照するオブジェクトを「that」として格納し、子の関数スコープが適用されるコールバック関数から参照しています。このようにある時点のthisを別の変数に代入する場合、その変数名としては「that」や「self」が一般的に使われます。

callとapplyによるthisの指定

実はthisが参照するオブジェクトを明示的に指定する方法があります。関数オブジェクトが標準で持っているcall/applyメソッドを使う方法です。

call/applyメソッドは引数にthisで参照させたいオブジェクトを指定できます。callは、関数の引数をカンマで指定していくのに対してapplyは配列で一気にしていできます。関数の引数が1つであればcall、複数の引数を取る場合はapplyを使うのがいいですね。

call/applyの構文

  • [関数].call([オブジェクト], [関数の引数1], [関数の引数2], …);
  • [関数].apply([オブジェクト], [[関数の引数1], [関数の引数2]]);

さきほどのAjaxのサンプルを劇的に変化させることはできませんが、コールバック関数でthisを使い、そのthisが指定したオブジェクトを参照するようにしてみましょう。

JS call/applyによるthisの指定

thisをコントロールしたいとき、call/applyの利用が選択肢に入れることができるように覚えておきたいですね。

所感

JavaScriptのthisについて見てきました。
個人的な所感としては実際に手を動かして挙動を確認していくのが一番学習効率が良かったです。

call/applyはコードの再利用性やオブジェクト指向の開発で大きな効果を発揮するようです。自分はまだそこまでの大規模コード開発は経験していないですがちゃんと使えるようになりたいです。