2

別の関数を返す関数を作成しようとしています。各内部関数を実行するときに個別の情報が必要ですが、これは発生していません。説明が良くないことを知っているので、小さな例をまとめました。

            var testFn = function(testVal) {
                return (function(testVal) {
                    var test = testVal;

                    this.getVal = function() {
                        return test;
                    }

                    return that;

                })(testVal);
            }
            var a = testFn(4);
            var b = testFn(2);
            console.log(b.getVal(), a.getVal());

これは2、2を出力します。私が欲しいのは2、4を出力することです。これが完全に説明されていないことはわかっているので、何を達成しようとしているのかが明確でない場合、変数が2つの関数間で共有されているように見える理由を誰かが説明できますか?

ありがとう

4

3 に答える 3

3

このような ?

var testFn = function(testVal) {
  var test = testVal
  return {
    getVal: function() {
      return  test
    }
  }   
};

var ab = testFn (4)
var ac = testFn (2)

console.log(ab.getVal(),ac.getVal()) //4 //2

あなたのコードの問題はthis.getVal()/戻ることですthis

'this'はグローバルスコープを参照しているため/Window

Window.getVal()設定している瞬間に、グローバル名前空間と上書きを行っています。b = testFn (2) これにより、両方ともグローバルオブジェクトを参照し、常に同じメソッドを共有するため、aメソッドも上書きされます。getValgetVal

したがって、それらは同じクロージャを共有し、2を出力しています。

console.log("The same: " + (Window.a === Window.b)) // true
console.log("The same: " + (a === b)) // true

少し変更すると、次のことがわかります。

        var testFn = function(testVal) {
          var x = {}
            return (function(testVal) {
                var test = testVal;
                x.getVal = function () {
                  return test;
                }
                 return x

            })(testVal);
        }
        var a = testFn(4);
        var b = testFn(2);
        console.log(b.getVal(), a.getVal());//4 2

2つの異なるオブジェクトが返されるため、突然機能します(ただし、外側のクロージャーも必要ありません) console.log("The same: " + (a === b)) // false

これがJSbinsFirst / Secondです

ご理解いただければ幸いです。説明が苦手です。不明な点がございましたら、コメントを投稿してください。回答を更新します。

于 2012-12-10T13:02:15.460 に答える
2

この質問は、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たメソッドが上書きされるためです。getValvar a = testFn(4);

JavaScriptは関数レベルでスコープするため、すべての関数には独自のスコープがあります。

var x = 3;
function foo() {
  var x = 2;
  console.log(x);
};
console.log(x); //gives us 3
foo(); // logs 2

したがって、実行したいのは、グローバルスコープではなく、関数のコンテキストでその内部関数を実行することです。testFncallメソッドを使用して、特定のコンテキストで関数を実行できます。また、スクリーンキャストをcallapply録画しました。これについてはこれについて詳しく説明しています。の基本的な使用法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呼び出し時に上書きされなくなりますtestFnnewキーワードを使用してこれを行うことができます。キーワードに関するこの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());を与えます。24

私はJSBinに実用的な例を示しました。これは、問題を解決するのに役立つはずです。この例this.xがグローバルに関数内でどのように定義されているかに注意し、どれがログに記録されるかを確認してください。これで遊んで、うまくいけばそれが役に立つかもしれません。

于 2012-12-10T13:44:47.227 に答える
1

あなたが得る出力は(2,2)です。

var that = this;

実際に取得するのは、グローバルオブジェクト(ウィンドウ)
です。これは、JavaScriptコード内のすべてのグローバルメソッドと変数を保持するオブジェクトです。
(オブジェクトまたは関数の下にネストされていないすべての変数はグローバルであり、オブジェクト
の下にネストされていないすべての関数はグローバルであることに注意してください。つまり、関数の下にネストされている関数は引き続きグローバルです

したがって、設定すると:

var test = testVal;

this.getVal = function() {
    return test;
}

実際にグローバルオブジェクトに関数「getVal」を設定し、次の実行で同じ関数を再度設定します-最初の関数をオーバーライドします。
あなたが望む効果を達成するために、私はそれを作成して反対し、それを内部関数に返すことを提案します(@Glutamatが私の前に提案したように):

var testFn = function(testVal) {
        return new Object({
            getVal: function() {
                return testVal;
            }
        });
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());

このように、外部関数では、外部関数(testVal)に渡された変数を返す「getVal」と呼ばれる内部関数を持つオブジェクトを作成します。JSBinを試してみたい場合は、こちらをご覧ください
(@Glutamatにこのサイトを紹介していただきありがとうございます。聞いたことがないので、とてもかっこいいです:D)

于 2012-12-10T13:38:22.373 に答える