Buno Journals

It's what I do that defines me.

JavaScriptのthisとは何か

開眼!  JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質

thisとは

もっとも基本的な考え方は、

thisとは、関数を呼び出すオブジェクトへのリンク。 thisとは、関数のスコープ内で有効な値で、実行中の関数をプロパティまたはメソッドとして保持しているオブジェクトへの参照である。

よって、実際にthisが何を指しているかは、関数定義時ではなく、実行時のコンテキストに依存する

// このfooはグローバルオブジェクトのスコープで定義
 var foo = 'I am foo of global scope';

// このfooはmyObjectのプロパティ
var myObject = { foo: 'I am myObject.foo' }

var sayFoo = function() {
  console.log(this.foo);
};

myObject.sayFoo = sayFoo;

// グローバルスコープから実行
sayFoo(); // 出力: 'I am foo of global scope', thisはグローバルオブジェクト

// myObjectのメソッドとして実行
myObject.sayFoo(); // 出力: 'I am myObject.foo', thisはmyObject

※ 私が確認したところJSFiddleでは上記が一部期待通りに動かない。以下の動作が原因のようだが。

var foo = 'foo';
console.log(this.foo); // JSFiddle上では、出力: undefined

call()やapply()で実行する場合

function.call(object, . . . )function.apply(object, [. . .])の形でfunctionを実行した場合、 関数の呼び出し元は第一引数のobjectになる。 つまり、関数内のthisが参照するのは、このobjectだ。

call()やapply()で関数を呼び出すと、その関数内のthisが指すオブジェクトを自分で設定することができる。

var myObject = {};

var myFunction = function(param1, param2) {
  this.foo = param1;
  this.bar = param2;
  console.log(this);
}

// 出力: Window {..., foo: "foo", bar: "bar"…}
myFunction('foo', 'bar');

// 出力: Object {foo: "foo", bar: "bar"}
myFunction.call(myObject, 'foo', 'bar');
myFunction.apply(myObject, ['foo', 'bar']);

入れ子関数の中のthis

二つ以上の関数を入れ子にした場合、前述の基本に反した動作をするので注意が必要だ。

入れ子関数の中のthisは、グローバルオブジェクトを参照する。

var myObject = {
  func1: function() {
    console.log(this); // 出力: myObject
    var func2 = function() {
      console.log(this); // 出力: window(グローバルオブジェクト)
    }();
  }
};

myObject.func1();

この仕様はECMAScript5で修正されるという記載があったが、 現時点Chromeで確認してもこの通りだっった。

OSX El Capitan 10.11.3, Google Chrome 51.0.2704.84 (Official Build) (64 ビット) で確認

コンストラクタ関数の場合

コンストラクタ関数内のthisが何を指すかは、new演算子を使って実行したか否かで変わる。

var Person = function(name) {
  this.name = name
}

// newあり。インスタンス生成
var bonnie = new Person('Bonnie Parker');
console.log(bonnie); // 出力: Person {name: "Bonnie Parker"}

// new無し。ただの関数実行
var clyde = Person('Clyde Barrow');
console.log(clyde); // 出力: undefined
console.log(window.name); // 出力: Clyde Barrow

newでコンストラクタを実行した場合、インスタンスが生成される。 そして、コンストラクタ関数内のthisはこの生成されたインスタンスである。

new無しの場合、ただの関数呼び出しであるので、上記の場合だとthisはグローバルオブジェクト(window)になる。

参考

開眼!  JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質

developer.mozilla.org

qiita.com