この質問は、JavaScriptで関数が呼び出されるコンテキストに帰着します。
別の関数内で呼び出される関数は、グローバルスコープのコンテキストで実行されます。
あなたの例では、あなたはこのコードを持っています:
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return this;
})(testVal);
}
内部関数はグローバルスコープで呼び出されているためthis
、グローバルオブジェクトを参照します。JavaScriptでは、別の関数内で実行される関数は、そのスコープがその関数内に存在する関数のスコープではなく、グローバルスコープに設定された状態で実行されます。これは開発者をかなりつまずかせる傾向があります(または少なくとも、私はそうします!)。
議論のために、これがブラウザにあると仮定しましょう。したがってthis
、オブジェクトを参照しwindow
ます。2
これが2回ログに記録される理由です。これは、2回目の実行時に、実行時に定義されthis.getVal
たメソッドが上書きされるためです。getVal
var a = testFn(4);
JavaScriptは関数レベルでスコープするため、すべての関数には独自のスコープがあります。
var x = 3;
function foo() {
var x = 2;
console.log(x);
};
console.log(x); //gives us 3
foo(); // logs 2
したがって、実行したいのは、グローバルスコープではなく、関数のコンテキストでその内部関数を実行することです。testFn
call
メソッドを使用して、特定のコンテキストで関数を実行できます。また、スクリーンキャストをcall
apply
録画しました。これについては、これについて詳しく説明しています。の基本的な使用法call
は次のとおりです。
function foo() {...}.call(this);
foo
これは、のコンテキストで実行されますthis
。したがって、最初のステップは、内部関数がメソッドのコンテキストである正しいコンテキストで呼び出されることを確認することtestFn
です。
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return this;
}.call(this, testVal);
}
の最初のパラメーターcall
はコンテキストであり、それに続く引数はパラメーターとして関数に渡されます。したがって、現在、内部関数は正しいスコープで呼び出されていますがgetVal
、グローバルスコープに追加されることはありません。これは、正しい方向へのステップです:)
次に、呼び出すたびtestFn
に新しいスコープで呼び出すことも確認する必要があります。これにより、2回目のthis.getVal
呼び出し時に上書きされなくなりますtestFn
。new
キーワードを使用してこれを行うことができます。キーワードに関するこのSO投稿は、new
読む価値があります。var foo = new testFn()
の新しいインスタンスを作成して実行するときはtestFN
、これにより新しいスコープを作成します。このSOの質問も関連しています。
あなたが今する必要があるのは、との宣言を変更することだけa
ですb
:
var a = new testFn(4);
var b = new testFn(2);
そして今、必要に応じて、console.log(b.getVal(), a.getVal());
を与えます。2
4
私はJSBinに実用的な例を示しました。これは、問題を解決するのに役立つはずです。この例this.x
がグローバルに関数内でどのように定義されているかに注意し、どれがログに記録されるかを確認してください。これで遊んで、うまくいけばそれが役に立つかもしれません。