We're looking for a user researcher to understand the needs of developers and designers. Is this you or someone you know? Check out the post: https://mzl.la/2IGzdXS

関数の this キーワード は、JavaScript ではほかの言語と少々異なる動作をします。また、strict モード と非 strict モードでも違いがあります。

ほとんどの場合、this の値は、関数の呼ばれ方によって決定されます。これは実行時に割り当てできず、関数が呼び出されるたびに異なる可能性があります。ES5 で 呼び出し方にかかわらず関数の this の値を設定するためにbind メソッドが導入され、ECMAScript 2015 で this がレキシカルスコープである(囲まれている実行コンテクストの this 値を設定する)アロー関数 が導入されました。

構文

this

グローバルコンテクスト

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

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

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

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"

関数コンテクスト

関数内では、this の値は関数の呼び出され方によって異なります。

単純な呼び出し

  下記のコードは strict モードではないため、また呼び出し時に this の値がセットされないため、this はデフォルトでグローバルオブジェクトとなり、それはブラウザーでは window です。

function f1(){
  return this;
}

// ブラウザー上で
f1() === window; // グローバルオブジェクト

// Node で:
f1() === global; // true

strict モードでは、this の値は実行コンテクストに入ったときに設定された値が残ります。なので、下記の場合は undefined が残ります。

function f2(){
  "use strict"; // strict モードを見てください。
  return this;
}

f2() === undefined; // true

よって strict モードでは、 this が実行コンテキストによって定義されない場合、 undefined のままです。

2 つ目の例では、f2 は直接呼び出されており、オブジェクトのメソッドやプロパティ(たとえば、window.f2())ではないため、thisundefined です。strict モード が初めてサポートされ始めたとき、いくつかのブラウザではこの機能が実装されませんでした。結果的に、それらのブラウザは不正確にも window オブジェクトを返していました。

別のコンテキストからthis渡すには call または apply を使用します。

// An object can be passed as the first argument to call or apply and this will be bound to it.
var obj = {a: 'Custom'};

// This property is set on the global object
var a = 'Global';

function whatsThis(arg) {
  return this.a;  // The value of this is dependent on how the function is called
}

whatsThis();          // 'Global'
whatsThis.call(obj);  // 'Custom'
whatsThis.apply(obj); // 'Custom'

関数本体に this キーワードを使用する場合、すべての関数が Function.prototype から継承する call メソッドか apply メソッドを使用した呼び出しで、その値に特定のオブジェクトをバインドできます。

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

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

// The first parameter is the object to use as
// 'this', subsequent parameters are passed as 
// arguments in the function call
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

// The first parameter is the object to use as
// 'this', the second is an array whose
// members are used as the arguments in the function call
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

callapply は、this として渡された値がオブジェクトではない場合、内部の ToObject 操作を使用してオブジェクトに変換しようと試みることに注意してください。7'foo' のようなプリミティブが渡された場合、関連するコンストラクタを使用してオブジェクトに変換されます。たとえば、プリミティブの number の 7new Number(7) による場合のようにオブジェクトに変換され、string の 'foo'new String('foo') による場合のようにオブジェクトに変換されます。

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

bar.call(7);     // [object Number]
bar.call('foo'); // [object String]

 

bind メソッド

ECMAScript 5 で Function.prototype.bind が導入されました。f.bind(someObject) の呼び出しは、f と同じ内部とスコープを持つ新しい関数を生成し、ここが this が発生するオリジナルの関数ですが、関数がどのように使われるかにかかわらず、新しい関数では bind の最初の引数に永続的にバインドされます。

function f(){
  return this.a;
}

var g = f.bind({a: 'azerty'});
console.log(g()); // azerty

var h = g.bind({a: 'yoo'}); // bind only works once!
console.log(h()); // azerty

var o = {a: 37, f: f, g: g, h: h};
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty

アロー関数

アロー関数 では、this はそれを囲むレキシカルなコンテキストの this の値が設定されます。グローバルコードでは、グローバルオブジェクトが設定されます:

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

注: this 引数がアロー関数の実行時に call, bind, apply に渡されても無視されます。まだcallに引数を加えることはできますが、最初の引数(thisArg) は null をセットすべきです。.

// オブジェクトのメソッドとして呼び出す。
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

// call を使用して this の設定を試みる。
console.log(foo.call(obj) === globalObject); // true

// bind を使用して this の設定を試みる。
foo = foo.bind(obj);
console.log(foo() === globalObject); // true

何があっても、foothis は生成されたときの値が設定されています(上記の例では、グローバルオブジェクトです)。同様のことが、ほかの関数内で生成したアロー関数にも適用されます:それらの this には、外部の実行コンテクストのものが設定されます。

// this を返す 関数を返す bar メソッドを持つ obj を生成します。
// 返された関数はアロー関数として生成されているため、その this は、 
// 永続的にその囲まれた関数の this に拘束されます。
// bar の値は呼び出し時に設定でき、戻り値の関数の値に順に設定します。
var obj = { bar : function() {
                    var x = (() => this);
                    return x;
                  }
          };

// obj のメソッドとして呼び出し、その this を obj に設定します。
// 戻り値の関数への参照を fn に割り当てます。
var fn = obj.bar();

// strict モードでは、this を設定せずに fn を呼び出すと
// 通常はグローバルオブジェクトか undefined が既定値となります。
console.log(fn() === obj); // true

// しかし obj のメソッドをcallすることなく参照するのは要注意です。
var fn2 = obj.bar;
// するとアロー関数の呼び出しで this は bar の this に従うため window と同じになります。
console.log(fn2()() == window); // true

上記では、関数(この匿名関数を A と呼びます)に obj.bar が返すアロー関数として生成されたほかの関数(この匿名関数を B と呼びます)を割り当てています。結果として、呼び出されたときに関数 B の this は、永続的に obj.bar(関数 A) の this が設定されます。返された関数(関数 B)が呼びされるとき、その this は常に最初に設定されたものになります。上記のコード例では、関数 B の this は obj である関数 A の this が設定されているため、通常はその thisundefined かグローバルオブジェクト(または、以前の例のグローバルコンテキストのように、いずれかのメソッド)が設定されますが、 obj の設定が残ります。

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

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

次の例では、o.f() が起動したとき、関数内の this には、o オブジェクトが関連付けられます。

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

console.log(o.f()); // logs 37

この振る舞いは、関数定義の方法や場所に全く影響を受けないことに注意してください。前述の例では、o の定義中に f メンバーとして関数をインラインに定義しています。しかし、関数を最初に定義して、後から o.f に付け足すことができます。その結果は同じ振る舞いになります:

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // 37

これは、関数が of のメンバーとして呼び出されることだけが重要なことを示しています。

同様に、this のバインディングは、最も直近のメンバー参照にのみ影響を受けます。次の例では、関数が呼び出すとき、オブジェクト o.bg メソッドとして呼び出しています。実行時に、関数内の thiso.b を参照します。オブジェクト自体が o のメンバーであるという事実は何の意味もありません:最も直近の参照のみが重要なのです。

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42

オブジェクトのプロトタイプチェーン上の this

同じ概念が、オブジェクトのプロトタイプチェーンのどこかに定義されたメソッドにも当てはまります。メソッドがオブジェクトのプロトタイプチェーン上にあった場合、メソッドがオブジェクト上にあるかのように、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 プロパティを持たず、プロトタイプから継承しています。しかし、f に対する検索が、最終的に o でその名前を持つメンバーを見つけることは重要ではありません; 検索は p.f への参照から開始されるため、関数内の thisp として参照されるオブジェクトの値を取ります。fp のメソッドとして呼ばれたため、その thisp を参照します。これは、JavaScript のプロトタイプ継承の興味深い機能です。

ゲッター/セッターと this

再度、同じ概念が、ゲッターやセッターから呼ばれる関数にも当てはまります。ゲッターやセッターとして使用される関数は、このプロパティを設定するか、または得られている元のオブジェクトにバインドされている this を持ちます。

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); // logs 2, 6

コンストラクタとして

関数がコンストラクタとして(new キーワードとともに)使用されるとき、その this は生成された新しいオブジェクトにバインドされます。

コンストラクタの既定では、this で参照されるオブジェクトを返しますが、代わりにほかのオブジェクトを返すことができます(戻り値がオブジェクトではない場合、this オブジェクトが返されます)。

/*
 * 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); // logs 37


function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // logs 38

最後の例(C2)では、オブジェクトが構築中に返されたので、this がバインドされている新しいオブジェクトは単に破棄されています。(これは根本的に "this.a = 37;" ステートメントを死んだコードにしてしまっています。これは実行されるので、正確には死んだコードではありませんが、外部への影響がありません。)

DOM イベントハンドラとして

関数がイベントハンドラとして使用される場合、その this にはイベントを発火させた要素が設定されます(一部のブラウザでは、 addEventListener メソッド以外では動的にリスナを追加する規則に従いません)。

// When called as a listener, turns the related element blue
function bluify(e){
  // Always true
  console.log(this === e.currentTarget); 
  // true when currentTarget and target are the same object
  console.log(this === e.target);
  this.style.backgroundColor = '#A5D9F3';
}

// Get a list of every element in the document
var elements = document.getElementsByTagName('*');

// Add bluify as a click listener so when the
// element is clicked on, it turns blue
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}

インラインイベントハンドラ内

コードがインライン on-event handler から呼ばれたとき、その this にはリスナが配置されている DOM 要素が設定されます:

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

上記の alert は button を表示します。外側のコードがこのように設定された this を持っているだけだということに注意してください。

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

この場合、内側の関数の this は設定されていないので、グローバルか window オブジェクトを返します(つまり、this が呼び出しによって設定されていないので、非 strict モードの既定オブジェクトです)。

仕様

仕様 ステータス コメント
ECMAScript Latest Draft (ECMA-262)
The this keyword の定義
ドラフト  
ECMAScript 2015 (6th Edition, ECMA-262)
The this keyword の定義
標準  
ECMAScript 5.1 (ECMA-262)
The this keyword の定義
標準  
ECMAScript 3rd Edition (ECMA-262)
The this keyword の定義
標準  
ECMAScript 1st Edition (ECMA-262)
The this keyword の定義
標準 初期定義。JavaScript 1.0 で実装。

ブラウザ実装状況

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
基本対応 あり あり1 あり あり あり
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
基本対応 あり あり あり4 あり あり あり

関連項目

ドキュメントのタグと貢献者

このページの貢献者: Uemmra3, unz, 676Masanori, YuichiNukiyama, teoli, ethertank, Potappo
最終更新者: Uemmra3,