this

JavaScriptでの関数のthisキーワードは、他の言語と比べて少し異なる振る舞いをします。 また、strictモードと非strictモード間でも幾つか違いがあります。

ほとんどの場合、thisの値はどのように関数が呼ばれたかによって決定されます。 実行中の割り当てによって設定することは出来ず、 関数の呼び出しごとに値が異なる可能性があります。 ES(ECMA Script)5で実装されたbindメソッドは、 関数がどのように呼び出されたかに関係なく関数のthis値を設定します。

文法

this

グローバルコンテキスト

グローバル実行コンテキスト内(関数の外)では、 strictモードであるか否かに関わらず、thisはグローバルオブジェクトを参照します。

console.log(this.document === document); // true

// Webブラウザでは、windowオブジェクトは、
// グローバルオブジェクトでもあります。
console.log(this === window); // true

this.a = 37;
console.log(window.a); // 37

関数コンテキスト

関数内では、thisの値は関数の呼び出し方によって変わります。

単純な呼び出し

function f1(){
  return this;
}

f1() === window; // グローバルオブジェクト

この場合、thisの値は呼び出しによって設定されません。 このコードはstrictモードでは無いため、 thisの値は常にデフォルトであるグローバルオブジェクトになります。

function f2(){
  "use strict"; // strictモードを参照
  return this;
}

f2() === undefined;

strictモードでは、thisの値は実行コンテキストに入った時の何かしら設定された値のままです。 もし、何も定義されていなければ、undefinedのままになります。 これには、null42"I am not this"のような様々な値を設定可能です。

注意: 2つ目の例では、f2は何かしらの土台無し(例: window.f2())に実行されているため、this値はundefinedのはずです。 この機能は、strictモードのサポートが最初にサポートされた際に、 幾つかのブラウザでは実装されていませんでした。 そのため、適切ではないwindowオブジェクトを返します。

オブジェクトのメソッドとして

関数がオブジェクトのメソッドとして呼び出された場合、 そのthis値には、そのメソッドを呼び出したオブジェクトが設定されます。

下記の例は、o.f()が実行された際に、 関数内部のthisはそのoオブジェクトにバインドされます。

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // 37を出力

thisの振る舞いは、関数がどのようにまたは何処で定義されたかに影響されないことに注意してください。 上記の例は、oの定義中にfメンバとして内部関数を定義しています。 ただし、最初に単に関数だけを定義して、後からo.fを割り当てることも出来ます。 下記の例は、結果的に同じ動作をします。

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // 37を出力

このデモで重要なことは、関数はofメンバーから実行されているという事です。

同様に、thisのバインドは、直近のメンバー参照によってのみ影響を受けます。 下記は、オブジェクトo.bのメソッドgとして、 関数を実行している例になります。 これが実行されている際に、関数内部のthiso.bを参照します。 そのオブジェクト自身がoのメンバーであるという事実は、 何の影響も及ぼしません。 直近の参照にとっては、それが全てです。

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42を出力
オブジェクトのprototypeチェーン上でのthis

これまでに説明したthisの概念は、オブジェクトのprototypeチェーン上の何処にメソッドが定義されても同様です。 メソッドがオブジェクトのprototypeチェーン上にある場合、 thisはメソッドを呼び出したオブジェクトを参照します。

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

この例では、変数pに割り当てられたオブジェクトは、 自身のfプロパティを持たず、prototypeからそれを継承します。 ただし、fのために、 oの名前を持つメンバーが最終的に見つけ出されることは重要ではありません。 p.fとして参照しようとすると、 関数内部のthispを参照した上で、オブジェクトの値を取得します。 fpのメソッドとして呼び出されるため、 そのthispを参照します。 これは、JavaScriptのプロトタイプ(prototype)継承の興味深い機能です。

thisによるgetterとsetter

繰り返しになりますが、これまでに説明したthisの概念は、関数がgetterまたはsetterから実行されても同様です。 getterまたはsetterとして使用される関数は、 そのプロパティの設定元または取得元から、 そのオブジェクトへバインドされたthisを持ちます。

function modulus(){
  return Math.sqrt(this.re * this.re + this.im * this.im);
}

var o = {
  re: 1,
  im: -1,
  get phase(){
    return Math.atan2(this.im, this.re);
  }
};

Object.defineProperty(o, 'modulus', {
    get: modulus,
    enumerable:true,
    configurable:true
});

console.log(o.phase, o.modulus); // -0.78 1.4142 を出力
コンストラクタで使用

関数がコンストラクタ(newキーワードと一緒に)として使用される場合、 そのthisはコンストラクタ(構築)される新しいオブジェクトにバインドされます。

注意: デフォルトではコンストラクタはthisによって参照されるオブジェクトを返しますが、 代わりに別のオブジェクトを返すことも可能です。 (もし返される値がオブジェクトで無ければ、thisによって参照されるオブジェクトが返されます)

/*
 * コンストラクタは次のように動作します:
 *
 * function MyConstructor(){
 *   // 実際の関数本文のコードはここに書きます。
 *   // 割り当てたいプロパティをthis上に作成します。
 *   // 例えば、
 *   this.fum = "nom";
 *   // その他...
 *
 *   // この関数がオブジェクトを返す文を持つ場合、
 *   // そのオブジェクトはnew式の結果になります。
 *   // そうでなければ、new式の結果は、そのオブジェクトに
 *   // 現在バインドしているthisになります。
 *   // (一般的に見受けられるのは、ほとんどがこのケースです。)
 * }
 */

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出力

最後の例(C2)では、オブジェクトがコンストラクタ中に返されているため、 thisがバインドされた新しいオブジェクトは単純に破棄されます。 (これは、実質的に"this.a = 37;"の文を排除されたコード(dead code)にしています。 正確には実行されるため、排除されているわけでありませんが、 外から干渉できないため実質的にそうなっていると言えます。)

callとapply

関数がthisキーワードをその本文内で使用する場合、 そのthisの値を呼び出しする際に、 Function.prototypeから全ての関数に継承されるcallまたはapplyメソッドを使用することで、 特定のオブジェクトにバインドすることが可能です。

function add(c, d){
  return this.a + this.b + c + d;
}

var o = {a:1, b:3};

// 1つ目の引数は'this'として使用するオブジェクト、
// その後に続く引数は関数呼び出しに引数として
// 渡されるものです。
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

// 1つ目の引数は'this'として使用するオブジェクト、
// 2つ目の引数は関数呼び出しに引数として使用される要素を持つ
// 配列になります。
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

callapplyの呼び出しで、 もしthisとして渡す値がオブジェクトでは無い場合、 内部のToObjectオペレーションを使用して、 オブジェクトへの変換が試みまれる事に注意してください。 そのため、7や'foo'のようなプリミティブな値が渡されると 関連するコンストラクタを使用して変換が行われ、 プリミティブの数値7は、まるでnew Number(7)によって作られたオブジェクトであるように変換され、 文字列'foo'はまるでnew String('foo')によって作られたオブジェクトであるように変換されます。 下記は実際の例になります。

function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7); // [object Number]
bindメソッドについて

ECMAScript 5でFunction.prototype.bindが導入されました。 f.bind(someObject)の呼び出しは、fと同じ本文、同じスコープの新しい関数を作成しますが、 関数がどのように使用されるかに関係なく、 bindの1つ目の引数が、新しい関数のthisに永続的にバインドされます。

function f(){
  return this.a;
}

//fから、bindを使用して新しい関数gを作成
var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty
DOMイベントハンドラとしての使用

関数がイベントハンドラとして使用される場合、 そのthisにはイベント発火元が設定されます。 (一部のブラウザがこの規則に従わず、そういった場合は、 addEventListener以外のメソッドで直接リスナーを追加します。)

// リスナーとして呼び出された場合、関係する要素を青色にします。
function bluify(e){
  // 常にtrue
  console.log(this === e.currentTarget);
  // currentTargetとtargetが同じオブジェクトであれば、true
  console.log(this === e.target);
  this.style.backgroundColor = '#A5D9F3'; //青色
}

// document内の各要素のリストを取得
var elements = document.getElementsByTagName('*');

// クリックリスナーとしてbluifyを追加するため、
// 要素がクリックすると青色になります。
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}
インラインのイベントハンドラでの使用

インラインのハンドラからコードが呼び出された場合、 そのthisには、そのリスナー(onclick)が置かれたDOM要素が設定されます。

<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>

上記は"button"という文字列をアラートで表示します。 ただし、この外部コードだけが、この方法でそのthisを持つことに注意してください。

<button onclick="alert((function(){return this}()));">
  Show inner this
</button>

上記のケースでは、関数内部のthisは設定されないため、グローバル/windowオブジェクトを返します。 (つまり、非strictモードのデフォルトのオブジェクトのthisは、その呼び出しによって設定されません。)

仕様

ブラウザ互換性

デスクトップ
機能 Chrome Firefox
(Gecko)
IE Opera Safari
基本
モバイル
機能 Android Chrome for
Android
Firefox
Mobile
IE
Mobile
Opera
Mobile
Safari
Mobile
基本

関連項目

 Back to top

© 2017 Mozilla Contributors
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.

このページは、ページトップのURL先のMozilla Developer Network(以下、MDN)のコンテンツを翻訳した内容を基に構成されています。 構成について異なる点も含まれますので、下記の項目を確認し、必要に応じて元のコンテンツをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。

  • 特定のブラウザに特化しすぎている情報やあまりにも古い情報、 または試験的に導入されているようなAPIや機能については、省略していることがあります。
  • 例やデモについて、実際にページ内で動作させる関係で一部ソースコードを変更している場合や、 その例で使用しているコンテンツの単語や文章などを日本人向けに変更しいてる場合があります。
  • MDNの更新頻度が高いため、元のコンテンツと比べ情報が古くなっている可能性があります。
  • "訳注:"などの断わりを入れた上で、日本人向けの情報の追記を行っている事があります。