重複の可能性:
JS: var self = this?
JavaScript で記述された任意のコード (GitHub など) を見ると、多くの開発者は現在のオブジェクトを参照する代わりに使用var self = this
してから使用します。self
this
このアプローチの背後にある理論的根拠は何ですか?
重複の可能性:
JS: var self = this?
JavaScript で記述された任意のコード (GitHub など) を見ると、多くの開発者は現在のオブジェクトを参照する代わりに使用var self = this
してから使用します。self
this
このアプローチの背後にある理論的根拠は何ですか?
の値this
はコンテキストです。書き込みvar self = this
は、あるコンテキストでの値を保存してthis
、別のコンテキストで使用できるようにする方法です。
例:
function Test() {
var self = this;
console.log(this);
setTimeout(function() {
console.log(this);
console.log(self);
}, 1000);
}
プリント:
Test {}
Window 11918143#comment15869603_11918143
Test {}
の値が変更されていることに注意してthis
ください。ただし、を使用して元の値を参照できますself
。
これが機能するのは、JavaScriptの関数が字句スコープ内の変数を「クローズオーバー」するためです(これは、内部関数が外部関数で宣言された変数を参照できるという、より技術的な言い方です)。これが私たちが書く理由var self = this
です; 変数self
は、外部関数が戻ってからしばらく経つまで実行されない場合でも、すべての内部関数で使用できます。
たとえば、jQuery でコールバックを使用している場合、親関数の変数を参照したい場合がありthis
ます。この変数は、別の関数では別の値を取ります。
$('#foo').click(function() {
var self = this;
$.get('foo.php', function(data) {
// In here, self != this
$(self).text(data);
});
});
この場合、 で置き換えても機能$(self)
し$(this)
ません。基本的に、this
後で使用するために変数に格納しています。
通常、コード内にネストされた関数宣言があり、「子」関数内から「親」関数を参照したい場合。
Ext.define('MyPanel', {
extend: 'Ext.panel.Panel',
title: 'My Panel',
initComponent: function() {
var self = this;
Ext.applyIf(self, {
items: [
{
xtype: 'button',
text: 'MyButton',
handler: function() {
console.log(this); //the button
console.log(self); //the panel
}}
]
});
self.callParent(arguments);
}
});
Ext.onReady(function() {
var p = new MyPanel({
renderTo: Ext.getBody()
});
});
例:
もう少し技術的な説明をさせてください。Javascript で変数にアクセスすると、インタープリターはスコープ スタックと呼ばれるもので変数の値を探します。オブジェクトのスタックと考えることができます。インタプリタは最初にスタックの一番上を調べます。変数がそのスコープ オブジェクトで定義されていない場合、変数はその下のオブジェクトを調べます。そこにない場合、インタプリタはスタックの一番下に到達するまで別のレベルを調べます。
最初は、スタック内の唯一のスコープ オブジェクトはグローバル オブジェクトです。変数が存在するかどうか。関数を呼び出すと、インタープリターは新しいオブジェクトをスコープ スタックにプッシュします。これは、ローカル変数の格納に使用されます。var1にアクセスすると、インタープリターは最初にローカル スコープ オブジェクトを調べます。そこにある場合は、そこに格納されている値を使用します。そうでない場合は、スタックのさらに下にあるスコープ オブジェクト (たまたまグローバル スコープ) に移動します。
関数内に関数を作成すると、興味深いことが起こります。インタープリターは、「アクティベーション オブジェクト」と呼ばれるものを作成します。これは基本的に、外部関数のローカル スコープ オブジェクトのスナップショットです。このアクティベーション オブジェクトは、内部関数に関連付けられます。内部関数が呼び出されると、アクティブ化オブジェクトはローカル スコープの前にスコープ スタックにプッシュされます (つまり、ローカル スコープは依然として一番上にあります)。内部関数内の変数へのアクセスは、インタープリターが最初にローカル スコープ オブジェクトをチェックし、次にアクティベーション オブジェクトをチェックし、次にグローバル スコープ オブジェクトをチェックすることを意味します。
定義により、this変数は常に関数のローカル スコープに存在します。常に暗黙の最初の引数を参照します。普通の関数を呼び出すと、コンパイラは null をthisとして渡します。変数は存在しますが、null を指しています。これを検索しても、ローカル スコープ オブジェクトを超えることはありません。
selfへの代入の目的は、基本的にインタープリターを騙して、内部関数のローカル スコープを超えて見えるようにすることです。内部関数でselfにアクセスすると、インタープリターはローカル スコープでそれを見つけられません。そのため、アクティベーション オブジェクトをチェックします。self = this ステートメントが内部関数の作成前に発生した場合、selfはアクティベーション スコープ オブジェクトに存在し、外部関数から見たthisオブジェクトを指します。