diff options
Diffstat (limited to 'files/ja/web/javascript/reference/operators/this/index.html')
-rw-r--r-- | files/ja/web/javascript/reference/operators/this/index.html | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/files/ja/web/javascript/reference/operators/this/index.html b/files/ja/web/javascript/reference/operators/this/index.html new file mode 100644 index 0000000000..25f4f68a40 --- /dev/null +++ b/files/ja/web/javascript/reference/operators/this/index.html @@ -0,0 +1,488 @@ +--- +title: this +slug: Web/JavaScript/Reference/Operators/this +tags: + - JavaScript + - Language feature + - Operator + - Primary Expressions + - Reference + - this + - 演算子 + - 言語機能 +translation_of: Web/JavaScript/Reference/Operators/this +--- +<div>{{jsSidebar("Operators")}}</div> + +<p><strong>関数の <code>this</code> キーワード</strong> は、JavaScript ではほかの言語と少々異なる動作をします。また、<a href="/ja/docs/Web/JavaScript/Reference/Strict_mode">厳格モード</a>と非厳格モードでも違いがあります。</p> + +<p>ほとんどの場合、<code>this</code> の値はどのように関数が呼ばれたかによって決定されます(実行時結合)。これは実行時に割り当てできず、関数が呼び出されるたびに異なる可能性があります。ES5 では、関数が{{jsxref('Operators/this', "どのように呼ばれたかに関係なく <code>this</code> の値を設定する", 'The_bind_method', 1)}} {{jsxref("Function.prototype.bind()", "bind()")}} メソッドが導入され、ES2015 では、独自の <code>this</code> バインディングを行わない<a href="/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions">アロー関数</a>が導入されました(これは包含するレキシカルコンテキストの <code>this</code> の値を保持します)。</p> + +<div>{{EmbedInteractiveExample("pages/js/expressions-this.html")}}</div> + +<div class="hidden">このデモのソースファイルは GitHub リポジトリに格納されています。デモプロジェクトに協力したい場合は、<a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> をクローンしてプルリクエストを送信してください。</div> + +<h2 id="Syntax" name="Syntax">構文</h2> + +<pre class="syntaxbox notranslate">this</pre> + +<h3 id="Value" name="Value">値</h3> + +<p>非厳格モードでは、実行コンテキスト (グローバル、関数、eval) のプロパティで、常にオブジェクトへの参照です。厳格モードではどのような値でも取り得ます。</p> + +<h2 id="解説">解説</h2> + +<h3 id="Global_context" name="Global_context">グローバルコンテキスト</h3> + +<p>グローバル実行コンテキスト (すべての関数の外側) では、厳格モードであるかどうかにかかわらず、<code>this</code> はグローバルオブジェクトを参照します。</p> + +<pre class="brush:js notranslate">// ウェブブラウザーでは window オブジェクトもグローバルオブジェクトです。 +console.log(this === window); // true + +a = 37; +console.log(window.a); // 37 + +this.b = "MDN"; +console.log(window.b) // "MDN" +console.log(b) // "MDN" +</pre> + +<div class="blockIndicator note"> +<p><strong>メモ:</strong> コードが実行されている現在のコンテキストに関係なく、グローバルの {{jsxref("globalThis")}} プロパティを使用していつでも簡単にグローバルオブジェクトを取得できます。</p> +</div> + +<h3 id="Function_context" name="Function_context">関数コンテキスト</h3> + +<p>関数内での <code>this</code> の値は、関数の呼び出され方によって異なります。</p> + +<p>下記のコードは<a href="/ja/docs/Web/JavaScript/Reference/Strict_mode">厳格モード</a>ではないため、また呼び出し時に <code>this</code> の値が設定されないため、<code>this</code> は既定でグローバルオブジェクトとなり、これはブラウザーでは {{domxref("Window", "window")}} です。</p> + +<pre class="brush:js notranslate">function f1() { + return this; +} + +// ブラウザー上で +f1() === window; // true + +// Node 上で +f1() === global; // true</pre> + +<p>ただし厳格モードでは、実行コンテキストに入るときに <code>this</code> 値が設定されていないと、以下の例のように <code>undefined</code> のままになります。</p> + +<pre class="brush:js notranslate">function f2() { + 'use strict'; // 厳格モードにする + return this; +} + +f2() === undefined; // true +</pre> + +<div class="note">二番目の例において、<code>this</code> が {{jsxref("undefined")}} となるのは <code>f2</code> が直接呼び出されており、オブジェクトのメソッドやプロパティ (例えば <code>window.f2()</code>) ではないためです。この機能は初めて<a href="/ja/docs/Web/JavaScript/Reference/Strict_mode">厳格モード</a>への対応が始まったとき、一部のブラウザーが実装していませんでした。その結果、これらのブラウザーは不正確に <code>window</code> オブジェクトを返していました。</div> + +<p>関数の呼び出し時に <code>this</code> の値を特定の値に設定するには、以下の例のように {{jsxref("Function.prototype.call()", "call()")}} または {{jsxref("Function.prototype.apply()", "apply()")}} を使用します。</p> + +<h3 id="クラスコンテキスト">クラスコンテキスト</h3> + +<p><a href="/ja/docs/Web/JavaScript/Reference/Classes">クラス</a>は関数の機能であるため、クラスと関数の <code>this</code> の動作は似ています。ただし、いくつかの違いと注意点があります。</p> + +<p>クラスのコンストラクター内では、<code>this</code> は通常のオブジェクトです。クラス内のすべての非静的メソッドは <code>this</code> のプロトタイプに追加されます。</p> + +<pre class="brush: js notranslate">class Example { + constructor() { + const proto = Object.getPrototypeOf(this); + console.log(Object.getOwnPropertyNames(proto)); + } + first(){} + second(){} + static third(){} +} + +new Example(); // ['constructor', 'first', 'second'] +</pre> + +<div class="blockIndicator note"> +<p><strong>メモ:</strong> 静的メソッドは <code>this</code> のプロパティではありません。それらはクラス自体のプロパティです。</p> +</div> + +<h3 id="派生クラス">派生クラス</h3> + +<p>基本クラスのコンストラクターとは異なり、派生コンストラクターには初期の <code>this</code> バインディングがありません。{{jsxref("Operators/super", "super()")}} を呼び出すとコンストラクター内に <code>this</code> バインディングが作成され、基本的に以下のコードを評価する効果があります。ここで、Base は継承されたクラスです。</p> + +<pre class="brush: js notranslate">this = new Base();</pre> + +<div class="blockIndicator warning"> +<p><strong>警告:</strong> super() を呼び出す前に <code>this</code> を参照するとエラーが発生します。</p> +</div> + +<p>派生クラスは、<code>オブジェクト</code>を return するか、コンストラクターを持たない場合を除き、<code>super()</code> を呼び出す前に return することはできません。</p> + +<pre class="brush: js notranslate">class Base {} +class Good extends Base {} +class AlsoGood extends Base { + constructor() { + return {a: 5}; + } +} +class Bad extends Base { + constructor() {} +} + +new Good(); +new AlsoGood(); +new Bad(); // 参照エラー</pre> + +<h2 id="例">例</h2> + +<h3 id="関数コンテキスト内の_this">関数コンテキスト内の this</h3> + +<pre class="brush:js notranslate" dir="rtl">// オブジェクトを call や apply の最初の引数として渡すと、this がそれに結び付けられます +var obj = {a: 'Custom'}; + +// このプロパティはグローバルオブジェクトに設定されます +var a = 'Global'; + +function whatsThis() { + return this.a; // this の値は関数の呼び出し方によって変わります +function is called +} + +whatsThis(); // 関数内の this として 'Global' は設定されていないので、デフォルトではグローバル/ウィンドウオブジェクトになります。 +whatsThis.call(obj); // 関数内の this として 'Custom' が obj に設定されています +whatsThis.apply(obj); // 関数内の this として 'Custom' が obj に設定されています +</pre> + +<h3 id="this_とオブジェクト変換">this とオブジェクト変換</h3> + +<pre class="brush:js notranslate">function add(c, d) { + return this.a + this.b + c + d; +} + +var o = {a: 1, b: 3}; + +// 最初の引数は 'this' として使用する +// オブジェクトで、続く引数は関数呼び出しの +// 引数として使用されます。 +add.call(o, 5, 7); // 16 + +// 最初の引数は 'this' として使用する +// オブジェクトで、二番目の引数は関数呼び出しの +// 引数として使用される配列です。 +add.apply(o, [10, 20]); // 34 +</pre> + +<p>なお、非厳格モードにおいて、<code>call</code> と <code>apply</code> は、<code>this</code> として渡された値がオブジェクトではない場合、内部の <code>ToObject</code> 操作を利用してオブジェクトに変換しようします。<code>7</code> や <code>'foo'</code> のようなプリミティブが渡された場合、関連するコンストラクターを使用してオブジェクトに変換されます。たとえば、プリミティブの数値である <code>7</code> は <code>new Number(7)</code> であるかのようにオブジェクトに変換され、文字列の <code>'foo'</code> は <code>new String('foo')</code> であるかのようにオブジェクトに変換されます。</p> + +<pre class="brush:js notranslate">function bar() { + console.log(Object.prototype.toString.call(this)); +} + +bar.call(7); // [object Number] +bar.call('foo'); // [object String] +bar.call(undefined); // [object global] +</pre> + +<h3 id="The_bind_method" name="The_bind_method"><code>bind</code> メソッド</h3> + +<p>ECMAScript 5 で {{jsxref("Function.prototype.bind")}} が導入されました。<code>f.bind(someObject)</code> の呼び出しは、<code>f</code> と同じ内部とスコープを持つ新しい関数を生成し、ここが <code>this</code> が発生するオリジナルの関数ですが、関数がどのように使われるかにかかわらず、新しい関数では <code>bind</code> の最初の引数に永続的にバインドされます。</p> + +<pre class="brush:js notranslate">function f() { + return this.a; +} + +var g = f.bind({a: 'azerty'}); +console.log(g()); // azerty + +var h = g.bind({a: 'yoo'}); // bind は一度しか機能しない +console.log(h()); // azerty + +var o = {a: 37, f: f, g: g, h: h}; +console.log(o.a, o.f(), o.g(), o.h()); // 37,37, azerty, azerty +</pre> + +<h3 id="Arrow_functions" name="Arrow_functions">アロー関数</h3> + +<p><a href="/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions">アロー関数</a>では、<code>this</code> はそれを囲むレキシカルコンテキストの <code>this</code> の値が設定されます。グローバルコードでは、グローバルオブジェクトが設定されます。</p> + +<pre class="brush: js notranslate">var globalObject = this; +var foo = (() => this); +console.log(foo() === globalObject); // true</pre> + +<div class="note"> +<p>メモ: アロー関数の呼び出し時に <code>this</code> 引数が <code>call</code>, <code>bind</code>, <code>apply</code> に渡されても無視されます。呼び出しに引数を加えることはできますが、最初の引数 (<code>thisArg</code>) は <code>null</code> を設定してください</p> +</div> + +<pre class="brush: js notranslate">// オブジェクトのメソッドとして呼び出す。 +var obj = {func: foo}; +console.log(obj.func() === globalObject); // true + +// call を使用して this の設定を試みる +console.log(foo.call(obj) === globalObject); // true + +// bind を使用して this の設定を試みる +foo = foo.bind(obj); +console.log(foo() === globalObject); // true</pre> + +<p>何があっても、<code>foo</code> の <code>this</code> は生成されたときの値が設定されています (上記の例ではグローバルオブジェクトです)。同様のことが、ほかの関数内で生成したアロー関数にも適用されます。それらの <code>this</code> には、それを包含するレキシカルコンテキストのものになります。</p> + +<pre class="brush:js notranslate">// this を返す関数を返す bar メソッドを持つ +// obj を生成します。返された関数はアロー関数 +// として生成されているため、その this は +// それを包含する関数の this に永続的に拘束 +// されます。bar の値は呼び出し時に設定でき、 +// 返値の関数の値に順に設定します。 +var obj = { + bar: function() { + var x = (() => this); + return x; + } +}; + +// bar を obj のメソッドとして呼び出す際、その this を obj に設定します +// 返値の関数への参照を fn に割り当てます。 +var fn = obj.bar(); + +// 厳格モードでは、this を設定せずに fn を呼び出すと +// 通常はグローバルオブジェクトか undefined が既定値となります。 +console.log(fn() === obj); // true + +// しかし obj のメソッドを call することなく参照するのは要注意です。 +var fn2 = obj.bar; +// するとアロー関数の呼び出しで this は bar の +// this に従うため window と同じになります。 +console.log(fn2()() == window); // true +</pre> + +<p>上記では、関数 (この無名関数を A と呼びます) に <code>obj.bar</code> が返すアロー関数として生成されたほかの関数 (この無名関数を B と呼びます) を割り当てています。結果として、呼び出されたときに関数 B の <code>this</code> は、永続的に <code>obj.bar</code> (関数 A) の <code>this</code> が設定されます。返された関数 (関数 B) が呼びされるとき、その <code>this</code> は常に最初に設定されたものになります。上記のコード例では、関数 B の <code>this</code> は <code>obj</code> である関数 A の <code>this</code> が設定されているため、通常はその <code>this</code> に <code>undefined</code> かグローバルオブジェクト (または、以前の例のグローバルコンテキストのように、いずれかのメソッド) が設定されますが、<code>obj</code> の設定が残ります。</p> + +<h3 id="As_an_object_method" name="As_an_object_method">オブジェクトのメソッドとして</h3> + +<p>関数がオブジェクトのメソッドとして呼び出されるとき、その <code>this</code> にはメソッドが呼び出されたオブジェクトが設定されます。</p> + +<p>次の例では、<code>o.f()</code> が起動したとき、関数内の <code>this</code> には、<code>o</code> オブジェクトが関連付けられます。</p> + +<pre class="brush:js notranslate">var o = { + prop: 37, + f: function() { + return this.prop; + } +}; + +console.log(o.f()); // 37 +</pre> + +<p>この振る舞いは、関数定義の方法や場所に全く影響を受けないことに注意してください。前述の例では、<code>o</code> の定義中に <code>f</code> メンバーとして関数をインラインに定義しています。しかし、関数を最初に定義して、後から <code>o.f</code> に付け足すことができます。その結果は同じ振る舞いになります。</p> + +<pre class="brush:js notranslate">var o = {prop: 37}; + +function independent() { + return this.prop; +} + +o.f = independent; + +console.log(o.f()); // 37 +</pre> + +<p>これは、関数が <code>o</code> の <code>f</code> のメンバーとして呼び出されることだけが重要なことを示しています。</p> + +<p>同様に、<code>this</code> の関連付けは、最も直近のメンバー参照にのみ影響を受けます。次の例では、関数が呼び出すとき、オブジェクト <code>o.b</code> の <code>g</code> メソッドとして呼び出しています。実行時に、関数内の <code>this</code> は <code>o.b</code> を参照します。オブジェクト自体が <code>o</code> のメンバーであるという事実は何の意味もありません。最も直近の参照のみが重要なのです。</p> + +<pre class="brush:js notranslate">o.b = {g: independent, prop: 42}; +console.log(o.b.g()); // 42 +</pre> + +<h4 id="this_on_the_objects_prototype_chain" name="this_on_the_objects_prototype_chain">オブジェクトのプロトタイプチェーン上の <code>this</code></h4> + +<p>同じ概念が、オブジェクトのプロトタイプチェーンのどこかに定義されたメソッドにも当てはまります。メソッドがオブジェクトのプロトタイプチェーン上にあった場合、メソッドがオブジェクト上にあるかのように、<code>this</code> はメソッドを呼び出したオブジェクトを参照します。</p> + +<pre class="brush:js notranslate">var o = {f: function() { return this.a + this.b; }}; +var p = Object.create(o); +p.a = 1; +p.b = 4; + +console.log(p.f()); // 5 +</pre> + +<p>この例では、変数 <code>p</code> に割り当てられたオブジェクト自身は <code>f</code> プロパティを持たず、プロトタイプから継承しています。しかし、<code>f</code> に対する検索が、最終的に <code>o</code> でその名前を持つメンバーを見つけることは重要ではありません。検索は <code>p.f</code> への参照から開始されるため、関数内の <code>this</code> は <code>p</code> として参照されるオブジェクトの値を取ります。<code>f</code> は <code>p</code> のメソッドとして呼ばれたため、その <code>this</code> は <code>p</code> を参照します。これは、JavaScript のプロトタイプ継承の興味深い機能です。</p> + +<h4 id="this_with_a_getter_or_setter" name="this_with_a_getter_or_setter">ゲッター/セッターと <code>this</code></h4> + +<p>再度、同じ概念が、ゲッターやセッターから呼ばれる関数にも当てはまります。ゲッターやセッターとして使用される関数は、このプロパティを設定するか、または得られている元のオブジェクトに関連付けられている <code>this</code> を持ちます。</p> + +<pre class="brush:js notranslate">function sum() { + return this.a + this.b + this.c; +} + +var o = { + a: 1, + b: 2, + c: 3, + get average() { + return (this.a + this.b + this.c) / 3; + } +}; + +Object.defineProperty(o, 'sum', { + get: sum, enumerable: true, configurable: true}); + +console.log(o.average, o.sum); // 2, 6 +</pre> + +<h3 id="As_a_constructor" name="As_a_constructor">コンストラクターとして</h3> + +<p>関数がコンストラクターとして ({{jsxref("Operators/new", "new")}} キーワードとともに) 使用されたとき、その <code>this</code> は生成された新しいオブジェクトに関連付けられます。</p> + +<div class="note"> +<p>コンストラクターの既定では、<code>this</code> で参照されるオブジェクトを返しますが、代わりにほかのオブジェクトを返すことができます (返値がオブジェクトではない場合、<code>this</code> オブジェクトが返されます)。</p> +</div> + +<pre class="brush:js notranslate">/* + * Constructors work like this: + * + * function MyConstructor(){ + * // Actual function body code goes here. + * // Create properties on |this| as + * // desired by assigning to them. E.g., + * this.fum = "nom"; + * // et cetera... + * + * // If the function has a return statement that + * // returns an object, that object will be the + * // result of the |new| expression. Otherwise, + * // the result of the expression is the object + * // currently bound to |this| + * // (i.e., the common case most usually seen). + * } + */ + +function C() { + this.a = 37; +} + +var o = new C(); +console.log(o.a); // 37 + + +function C2() { + this.a = 37; + return {a: 38}; +} + +o = new C2(); +console.log(o.a); // 38 +</pre> + +<p>最後の例 (<code>C2</code>) では、構築中にオブジェクトを返しているので、<code>this</code> が結び付けられている新しいオブジェクトは単に破棄されています。(これは根本的に "<code>this.a = 37;</code>" ステートメントを死んだコードにしてしまっています。これは実行されるので、正確には死んだコードではありませんが、外部への影響がありません。)</p> + +<h3 id="As_a_DOM_event_handler" name="As_a_DOM_event_handler">DOM イベントハンドラーとして</h3> + +<p>関数がイベントハンドラとして使用された場合、その <code>this</code> はリスナーが配置されている要素に設定されます ({{domxref("EventTarget/addEventListener", "addEventListener()")}} 以外のメソッドで動的に追加されたリスナーについては、この規約に従わないブラウザー-もあります)。</p> + +<pre class="brush:js notranslate">// リスナーとして呼び出された場合は、関連づけられた要素を青にする +function bluify(e) { + // 常に true + console.log(this === e.currentTarget); + // currentTarget と target が同じオブジェクトであれば true + console.log(this === e.target); + this.style.backgroundColor = '#A5D9F3'; +} + +// 文書内の各要素の一覧を取得 +var elements = document.getElementsByTagName('*'); + +// クリックリスナーとして bluify を追加することで、 +// 要素をクリックすると青くなるようになる +for(var i = 0 ; i < elements.length; i++){ + elements[i].addEventListener('click', bluify, false); +}</pre> + +<h3 id="In_an_inline_event_handler" name="In_an_inline_event_handler">インラインイベントハンドラー内</h3> + +<p>コードがインラインの <a href="/ja/docs/Web/Guide/Events/Event_handlers">on-イベントハンドラー</a>から呼び出されたとき、その <code>this</code> にはリスナーが配置されている DOM 要素が設定されます。</p> + +<pre class="brush:js notranslate"><button onclick="alert(this.tagName.toLowerCase());"> + Show this +</button> +</pre> + +<p>上記のアラートは <code>button</code> と表示します。ただし、外側のコードがこのように設定された <code>this</code> を持っているだけだということに注意してください。</p> + +<pre class="brush:js notranslate"><button onclick="alert((function() { return this; })());"> + Show inner this +</button> +</pre> + +<p>この場合、内側の関数の <code>this</code> は設定されていないので、グローバルの window オブジェクトを返します (つまり、<code>this</code> が呼び出しによって設定されていないので、非厳格モードの既定オブジェクトです)。</p> + +<h3 id="クラスの中の_this">クラスの中の this</h3> + +<div class="blockIndicator note"></div> + +<p>通常の関数と同様に、メソッド内の <code>this</code> の値は、どのように呼び出されるかによって異なります。クラス内の <code>this</code> が常にクラスのインスタンスを参照するように、この動作をオーバーライドしておくと便利な場合もあります。これを実現するには、コンストラクターでクラスのメソッドをバインドします。</p> + +<pre class="brush: js notranslate">class Car { + constructor() { + // 違いを示すために sayHi ではなく sayBye をバインドする + this.sayBye = this.sayBye.bind(this); + } + sayHi() { + console.log(`Hello from ${this.name}`); + } + sayBye() { + console.log(`Bye from ${this.name}`); + } + get name() { + return 'Ferrari'; + } +} + +class Bird { + get name() { + return 'Tweety'; + } +} + +const car = new Car(); +const bird = new Bird(); + +// メソッドの 'this' の値は呼び出し元に依存します +car.sayHi(); // Hello from Ferrari +bird.sayHi = car.sayHi; +bird.sayHi(); // Hello from Tweety + +// バインドされたメソッドの場合、'this' は呼び出し元に依存しません +bird.sayBye = car.sayBye; +bird.sayBye(); // Bye from Ferrari</pre> + +<div class="blockIndicator note"> +<p><strong>メモ:</strong> クラスは常に厳格モードのコードです。これを定義せずに <code>this</code> でメソッドを呼び出すとエラーが発生します。</p> +</div> + +<h2 id="Specifications" name="Specifications">仕様</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">仕様書</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('ESDraft', '#sec-this-keyword', 'The this keyword')}}</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_compatibility" name="Browser_compatibility">ブラウザーの互換性</h2> + +<div class="hidden">このページの互換性一覧表は構造化データから生成されています。データに協力していただけるのであれば、<a class="external" href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> をチェックアウトしてプルリクエストを送信してください。</div> + +<p>{{Compat("javascript.operators.this")}}</p> + +<h2 id="See_also" name="See_also">関連情報</h2> + +<ul> + <li><a href="/ja/docs/Web/JavaScript/Reference/Strict_mode">厳格モード</a></li> + <li><a href="https://dmitripavlutin.com/gentle-explanation-of-this-in-javascript/">Gentle explanation of 'this' keyword in JavaScript</a></li> + <li>Getting the global context: {{jsxref("globalThis")}}</li> +</ul> |