LoginSignup
1
6

More than 5 years have passed since last update.

javascript の「this」について

Last updated at Posted at 2018-07-29

グローバルコンテキスト

node.js

グローバル空間での this は{}

console.log(this); // {}
this.a = 'MDN';
console.log(this); // { a: 'MDN' }

Browser

グローバル空間での this はwindowオブジェクト

console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
this.a = 'MDN';
console.log(this); // Window {a: "MDN", postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}

関数コンテキスト

単純な呼び出し

node.js

this にはglobalオブジェクトが入る

function f1() {
  return this;
}
console.log(f1()); // console: [Getter],DTRACE_NET_SERVER_CONNECTION: [Function],DTRACE_NET_STREAM_END: [Function],…
console.log(f1() === global); // true

node.js + strict mode

strict mode だと this は未定義となる。

'use strict';
function f1() {
  return this;
}
console.log(f1()); // undefined
console.log(f1() === global); // false

Browser

グローバルコンテキスト同様、this には window オブジェクトが入る

function f1() {
  return this;
}
console.log(f1()); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
console.log(f1() === window); // true

Browser + strict mode

node.js 同様、stirct mode だと this は未定義となる

'use strict';
function f1() {
  return this;
}
console.log(f1()); // undefined
console.log(f1() === window); // false

別のコンテキストからの渡された this

call/applyで function 内の this を変更できる。

node.js

this.aは未定義になる。

var obj = { a: 'Custom' };
var a = 'Global';

function whatsThis(arg) {
  return this.a;
}

console.log(whatsThis()); // undefined
console.log(whatsThis.call(obj)); // 'Custom'
console.log(whatsThis.apply(obj)); // 'Custom'

Browser

this.avar aで宣言された値が入る。

var obj = { a: 'Custom' };
var a = 'Global';

function whatsThis(arg) {
  return this.a;
}

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

Browser/node.js + strict mode

thisが定義されていないため、プロパティに代入しようとした時点で TypeError が出力される。

'use strict';
var obj = { a: 'Custom' };
var a = 'Global';

function whatsThis(arg) {
  return this.a; // TypeError: Cannot read property 'a' of undefined
}

console.log(whatsThis());
console.log(whatsThis.call(obj));
console.log(whatsThis.apply(obj));

bind メソッドの this

Browser/node.js

bind を使用するとオリジナルの関数(f())と同じスコープを持つ新しい関数を生成する。thisは引数に渡されたオブジェクトに束縛される。
また、bind で生成された関数(g())から bind を呼び出しても、this の参照先は変わらない。

function f() {
  return this.a;
}

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

let h = g.bind({ a: 'yoo' });
console.log(h()); // azerty

h = f.bind({ a: 'yoo' });
console.log(h()); // yoo

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

アロー関数の this

アロー関数はそれを囲むオブジェクトを this として参照する。

以下の例ではアロー関数 x は bar メソッドを持つオブジェクト、つまり変数 obj を返す。

Browser/node.js

const obj = {
  bar: function() {
    const x = () => this;
    return x;
  }
};

const fn = obj.bar();
console.log(fn()); // { bar: [Function: bar] }
console.log(fn() === obj); // true

* strict mode であっても違いはない。

function だけでの呼び出しだと、global/window オブジェクトを返す。

function bar() {
  const x = () => this;
  return x;
}

const fn = bar();
console.log(fn()); // global/windowオブジェクト

strict mode だと未定義になる。

'use strict';
function bar() {
  const x = () => this;
  return x;
}

const fn = bar();
console.log(fn()); //undefined

補足 1

bar メソッ ドをアロー関数にするとどうなるか?

アロー関数自身はthisを束縛しないため、this は空のオブジェクトとなる。

const obj = {
  bar: () => {
    const x = () => this;
    return x;
  }
};

const fn = obj.bar();
console.log(fn()); // {}
console.log(fn() === obj); // false

補足 2

一度設定されたthisは生成されたときの値が設定される。
object のメソッドとしても、call/bind で呼び出しても this は{}のまま。

var foo = () => this;
console.log(foo()); // {}
var obj = { foo: foo };
console.log(obj.foo()); // {}
console.log(foo.call(obj)); // {}
foo = foo.bind(obj);
console.log(foo()); // {}

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

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

Browser/node.js

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

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

* strict mode であっても違いはない。

これはどんな定義の仕方でも変わらない。オブジェクトのメンバとして呼び出されることが重要。

const o = { prop: 37 };

function independent() {
  return this.prop;
}

o.f = independent;

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

当然だが、呼び出し元が変わると this も変わる。

const o = { prop: 37 };

function independent() {
  return this.prop;
}

o.f = independent;

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

* strict mode であっても違いはない。

オブジェクトのプロトタイプチェーン上の this の例もあったが...プロトタイプチェーンをいまいち理解していないため割愛...。

コンストラクタの this

関数をコンストラクタとして使用する時、this は生成された新しいオブジェクトを参照する。

C2は return 句でオブジェクトを返すため、this.aは参照されていない。

Browser/node.js

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

* strict mode であっても違いはない。

1
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
6