の簡単な概要this
this
JavaScript では動的にスコープされます。その動作は、レキシカル スコープの他のすべての変数とは異なります。他の変数は、関数の呼び出し方法に応じて異なるバインディングを持ちません。それらのスコープは、スクリプトに表示される場所から来ます。ただし、動作が異なり、スクリプト内のどこに表示されるかではなく、呼び出される方法this
に応じて異なるバインディングを持つことができます。そのため、この言語を学習している人にとっては混乱の元になる可能性がありますが、熟練した JavaScript 開発者になるには、それを習得する必要があります。
は動的にバインドされるためthis
、関数の呼び出し方法に基づいて値を変更する方法がいくつかあります。
例
JavaScript で関数を実行する場合、デフォルトthis
はwindow
です。
function foo() {
console.log(this);
}
foo(); // => window
this
値はさまざまな方法で変更できます。1 つの方法は、関数をオブジェクトのメソッドとして呼び出すことです。
var x = {
foo: function() {
console.log(this);
}
};
x.foo(); // => This time it's the x object.
もう 1 つの方法は、関数を使用するcall
かapply
、特定のオブジェクトのコンテキストで実行するように指示することです。
function foo() {
console.log(this);
}
foo.call(x); // => x object again
foo.apply(x); // => x object as well
call
またはapply
の場合null
、undefined
デフォルトの動作が再び発生します。関数は のコンテキストで実行されますwindow
。
function foo() {
console.log(this);
}
foo.call(null); // => window
foo.apply(undefined); // => window
ただし、ECMAScript 5 strict modeでは、this
デフォルトで window にならないことに注意してください:
(function() {
'use strict';
function foo() {
console.log(this);
}
foo(); // => undefined
foo.call(null); // => null
foo.apply(undefined); // => undefined
})();
this
を使用bind
して、関数が呼び出される前にオブジェクトにバインドすることもできます。
function foo() {
console.log(this);
}
var bar = {
baz: 'some property'
};
var foobar = foo.bind(bar);
foobar(); // => calls foo with bar as this
父になる: レイジー バインド / アンカリーイングthis
さらに進んで、 a に作用し、関数の最初の引数として値を渡すことがthis
できる関数を使用したい場合があります。this
これは、 などの配列メソッドに非常に役立ちますforEach
。たとえば、配列に似ているが実際には配列ではないオブジェクトを扱っているとします。
var arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
'length': 3
};
このオブジェクトを で反復処理する場合はforEach
、次を使用できますcall
。
Array.prototype.forEach.call(arrayLike, function(item) {
console.log(item);
});
// Logs: a, b, c
ただし、別のオプションはforEach
、オブジェクトで直接呼び出すことができる関数を作成することです。
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
これで、配列のようなオブジェクトを反復処理したいときはいつでもこの関数を使用できます。
forEach(arrayLike, function(item) {
console.log(item);
});
// Logs: a, b, c
この方法は「非カリー化this
」と呼ばれることもあります。ただし、これらの「カリー化されていない」関数を生成できる関数を作成し、それを「遅延バインディング」と呼ぶことを好みます。
var lazyBind = Function.prototype.bind.bind(Function.prototype.call);
var forEach = lazyBind(Array.prototype.forEach);
var slice = lazyBind(Array.prototype.slice);
var map = lazyBind(Array.prototype.map);
forEach(arrayLike, function(u) {
console.log(u);
});
// Logs: a, b, c
var realArray = slice(arrayLike);
// Converts arrayLike into a real array
forEach(
map(arrayLike, function(u) {
return u + 'Q';
}),
function(u) {
console.log(u);
}
);
// Logs: aQ, bQ, cQ
この手法の素晴らしい点の 1 つは、セキュリティ保護可能な JavaScript を作成するのに役立つことです。これは、ページ上の他のスクリプトが内部変数を詮索したくない場合に役立ちます。ただし、これはかなり高度なメタプログラミング手法であり、日常の JavaScript では見られません。