編集:
それは完全に単純です: サンプル ページでコンソールを開いて main.js のソースを見ると (左下隅にある のようなボタンをクリックします[{}]
)、スクリプト全体が 1 つの大きな関数であることがわかります。を使用して呼び出され.call(this)
ます。後者は、厳密モード (呼び出し元コンテキストとして明示的に設定されていない限り、グローバル オブジェクトを保護する) のために必要です。
この関数は、この関数のスコープ内のすべての関数、オブジェクト、およびメソッドを宣言し、クロージャーを形成します。したがって、このスコープで宣言されたすべての関数もすべての変数にアクセスできるのは当然のことです。最終的に、google
プロパティはグローバル オブジェクトのプロパティとして割り当てられるため、クロージャが公開されます。
(function()
{
'use strict';
console.log(this);//would be undefined
}).call(this);//but the global object is explicitly set as context, so this === window
(function()
{
'use strict';
var closureScope = 'Global object can\'t see me';
var google = {visible:'Yes, I was assigned as a property to the global object'};
google.closureScope = closureScope;//expose initial value of closureScopeVariable
google.showBenefits = function()
{//context here is google object, this points to google
this.closureScope = 'I looked like the closure variable';//reassign
console.log(this.closureScope === closureScope);//logs false
};
google.restoreOriginal = function()
{
this.closureScope = closureScope;//reassign closureScope's original value
};
//expose:
this.google = google;
}).call(this);
//global object:
google.closureScope = 'Foobar';
google.restoreOriginal();
console.log(google.closureScope);//Global object can't see me
私が知っている限りでは、これはそれほど明確に見えないかもしれませんが、基本的に何が起こるかは次のとおりです。各関数には独自のスコープがあります。そのスコープで宣言されたすべての変数は、それらを参照するオブジェクトがない限り、その関数が戻るときにガベージ コレクション (GC) されます。
この場合、google は無名関数のスコープで宣言されたオブジェクトです。次に、この google オブジェクトへの参照がグローバル オブジェクトに割り当てられました。たまたまオブジェクト変数と同じ名前になっていますが、次のように公開することもできます。
window.foobar = google;
window.foobar.closureScope;//works
window.google;//undefined
Google はグローバル オブジェクトのプロパティであり、関数のスコープで作成されたオブジェクトを参照します。それが参照するオブジェクトは、関数のスコープ (およびそのスコープで宣言されたすべての変数) を維持します。そのため、クロージャー変数にほぼ直接アクセスできるように見えるかもしれませんが、これもREFERENCEです。C(++) プログラミングに精通している場合、疑似コードでは次のようになります。
GoogleObj google = new Google();
GoogleObj &window.google = google;
//or in pseudo-C:
GoogleObj *google;
GoogleObj **window.google = &google;//pointer to pointer ~= reference
基本的に、グローバルgoogle
には実際のGoogleオブジェクトのメモリアドレス以外は何も含まれていません。それを指し、参照し、メモリ内の値を探す場所をJSに指示するだけです...
実際のオブジェクトに直接アクセスすることはできません。メモリのどこかに、それとともに宣言されたすべてのローカル変数もあり、それらにもすべてアドレスがありますが、グローバルオブジェクトはそれらについて知りません。知っている 1 つのアドレスに移動し、必要なものを要求すると、元のgoogle オブジェクトが従います。
私はこれらすべてを首尾一貫した包括的な方法で説明するのが苦手ですが、おそらくこの記事はこの問題に光を当てるかもしれません. クロージャーについて調べ始めたとき、図が非常に役立つことがわかりました。
そんなことはできません。クロージャーの要点は、その特定のスコープでのみ参照できる変数を設定できることです。ただし、できることは、特権メソッドを使用するか、(良い習慣ではありませんが可能です) グローバル オブジェクトに変数を完全に割り当てることです。
(function()
{
var name = 'foo';
//do stuff
window.name = name;//expose to global object
})();//THIS IS BLUNT AND DANGEROUS
var safer = (function()
{
var name = 'foo';
return {name:name};
});
console.log(safer.name);//logs foo
本当に、本当にグローバルが必要な場合:
var safer = (function()
{
var closureVars = {name:'foo'};
var name = 'foo';
return function(privateName,globalName)
{
globalName = globalName || privateName;
window[globalName] = closureVars[privateName];
};
});
safer('name');//sets window.name to 'foo'
しかし、何よりも、特にあなたの場合(特定の「プライベート」変数にアクセスする)、特権ゲッターが最善の方法のようです:
var module = (function()
{
var closureVars = {name:'foo';}
return {get:function(name)
{
return closureVars[name];
},
set:function(name,val)
{
closureVars[name] = val;
}
};
};
var name = module.get('name');//sets a global name variable to 'foo'
module.set('name2',module.get('name'));//and so on
それはそれを行う必要があります