グローバルコンテキスト
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.a
にvar 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 であっても違いはない。