3092

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

これを出力します:

私の価値:3
私の価値:3
私の価値:3

出力したいのですが:

私の価値:0
私の価値:1
私の価値:2


関数の実行の遅延がイベントリスナーの使用によって引き起こされた場合にも、同じ問題が発生します。

var buttons = document.getElementsByTagName("button");
// let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
  // as event listeners
  buttons[i].addEventListener("click", function() {
    // each should log its value.
    console.log("My value: " + i);
  });
}
<button>0</button>
<br />
<button>1</button>
<br />
<button>2</button>

…または非同期コード、たとえばPromisesの使用:

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for (var i = 0; i < 3; i++) {
  // Log `i` as soon as each promise resolves.
  wait(i * 100).then(() => console.log(i));
}

それはまたfor infor ofループで明らかです:

const arr = [1,2,3];
const fns = [];

for(var i in arr){
  fns.push(() => console.log(`index: ${i}`));
}

for(var v of arr){
  fns.push(() => console.log(`value: ${v}`));
}

for(var f of fns){
  f();
}

この基本的な問題の解決策は何ですか?

4

44 に答える 44

2327

問題は、i各無名関数内の変数が、関数外の同じ変数にバインドされていることです。

ES6ソリューション:let

ECMAScript 6(ES6)は、ベース変数とは異なるスコープの新しいキーワードを導入letしています。たとえば、ベースのインデックスを持つループでは、ループを繰り返すたびにループスコープを持つ新しい変数が含まれるため、コードは期待どおりに機能します。多くのリソースがありますが、優れた情報源として2alityのブロックスコープ投稿をお勧めします。constvarleti

for (let i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("My value: " + i);
  };
}

ただし、Edge 14より前のIE9-IE11とEdgeはサポートletしますが、上記が間違っていることに注意してください(i毎回新しい関数が作成されるわけではないため、上記のすべての関数は、使用した場合と同じように3をログに記録しますvar)。エッジ14はついにそれを正しくします。


ES5.1ソリューション:forEach

関数が比較的広く利用可能になっているためArray.prototype.forEach(2015年)、主に値の配列に対する反復を伴う状況で.forEach()は、反復ごとに明確なクロージャを取得するためのクリーンで自然な方法が提供されることに注意してください。つまり、値(DOM参照、オブジェクトなど)を含むある種の配列があり、各要素に固有のコールバックを設定する際に問題が発生すると仮定すると、次のように実行できます。

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
  // ... code code code for this one element
  someAsynchronousFunction(arrayElement, function() {
    arrayElement.doSomething();
  });
});

アイデアは、ループで使用されるコールバック関数の各呼び出しが.forEach独自のクロージャーになるということです。そのハンドラーに渡されるパラメーターは、反復のその特定のステップに固有の配列要素です。非同期コールバックで使用される場合、反復の他のステップで確立された他のコールバックのいずれとも衝突しません。

jQueryで作業している場合、この$.each()関数は同様の機能を提供します。


古典的な解決策:クロージャ

実行したいのは、各関数内の変数を、関数外の個別の不変の値にバインドすることです。

var funcs = [];

function createfunc(i) {
  return function() {
    console.log("My value: " + i);
  };
}

for (var i = 0; i < 3; i++) {
  funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

JavaScriptにはブロックスコープがなく、関数スコープのみであるため、関数の作成を新しい関数でラップすることにより、「i」の値が意図したとおりに維持されるようにします。

于 2009-04-15T06:18:17.527 に答える
405

試す:

var funcs = [];
    
for (var i = 0; i < 3; i++) {
    funcs[i] = (function(index) {
        return function() {
            console.log("My value: " + index);
        };
    }(i));
}

for (var j = 0; j < 3; j++) {
    funcs[j]();
}

編集(2014):

個人的には、@ Austの使用に関する最近の回答.bindが、この種のことを今行うための最良の方法だと思います。's_.partialをいじる必要がない、またはいじりたくない場合は、lo-dash/underscoreもあります。bindthisArg

于 2009-04-15T06:10:50.947 に答える
285

インデックス変数を囲む最も簡単で読みやすい方法は、すぐに呼び出される関数式を使用することです。

for (var i = 0; i < 3; i++) {

    (function(index) {

        console.log('iterator: ' + index);
        //now you can also loop an ajax call here 
        //without losing track of the iterator value:   $.ajax({});
    
    })(i);

}

これは、イテレータiを として定義する無名関数に送信しますindexiこれにより、IIFE 内の非同期機能で後で使用するために変数が保存されるクロージャーが作成されます。

于 2013-10-11T18:23:43.657 に答える
176

パーティーに少し遅れましたが、今日この問題を調査していて、多くの回答が Javascript がスコープを処理する方法に完全に対応していないことに気付きました。

他の多くの人が述べたように、問題は内部関数が同じi変数を参照していることです。では、反復ごとに新しいローカル変数を作成し、代わりに内部関数がそれを参照するようにしないのはなぜでしょうか?

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    var ilocal = i; //create a new local variable
    funcs[i] = function() {
        console.log("My value: " + ilocal); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

以前と同様に、各内部関数は に割り当てられた最後の値を出力しましたがi、今では各内部関数は に割り当てられた最後の値を出力するだけilocalです。しかし、各反復には独自のものがあるべきではありませんilocalか?

結局のところ、それが問題です。各反復は同じスコープを共有しているため、最初の反復以降のすべての反復は上書きするだけilocalです。MDNから:

重要: JavaScript にはブロック スコープがありません。ブロックで導入された変数は、それを含む関数またはスクリプトにスコープされ、それらを設定した効果はブロック自体を超えて持続します。つまり、ブロック ステートメントはスコープを導入しません。「スタンドアロン」ブロックは有効な構文ですが、JavaScript ではスタンドアロン ブロックを使用したくありません。なぜなら、C や Java でそのようなブロックのようなことをすると思ったとしても、あなたが思っていることをしないからです。

強調のために繰り返します:

JavaScript にはブロック スコープがありません。ブロックで導入された変数は、それを含む関数またはスクリプトにスコープされます

ilocalこれは、各反復で宣言する前に確認することで確認できます。

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
  console.log(ilocal);
  var ilocal = i;
}

これがまさに、このバグが非常にトリッキーな理由です。変数を再宣言しても、Javascript はエラーをスローせず、JSLint は警告をスローしません。これが、これを解決する最善の方法がクロージャーを利用することである理由でもあります。これは、本質的に、Javascript では、内側のスコープが外側のスコープを「囲む」ため、内側の関数が外側の変数にアクセスできるという考えです。

閉鎖

これは、内部関数が外部変数を「保持」し、外部関数が戻った場合でもそれらを存続させることも意味します。ilocalこれを利用するには、新しいスコープを作成し、新しいスコープで宣言し、使用する内部関数を返すためだけにラッパー関数を作成して呼び出しますilocal(詳細は以下を参照)。

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() { //create a new scope using a wrapper function
        var ilocal = i; //capture i into a local var
        return function() { //return the inner function
            console.log("My value: " + ilocal);
        };
    })(); //remember to run the wrapper function
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

ラッパー関数内に内部関数を作成すると、内部関数だけがアクセスできるプライベート環境である「クロージャ」が内部関数に与えられます。したがって、ラッパー関数を呼び出すたびに、独自の別の環境で新しい内部関数を作成し、ilocal変数が衝突して互いに上書きしないようにします。いくつかのマイナーな最適化により、他の多くの SO ユーザーが与えた最終的な答えが得られます。

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = wrapper(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}
//creates a separate environment for the inner function
function wrapper(ilocal) {
    return function() { //return the inner function
        console.log("My value: " + ilocal);
    };
}

アップデート

ES6 が主流になったため、 newletキーワードを使用してブロックスコープの変数を作成できるようになりました。

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (let i = 0; i < 3; i++) { // use "let" to declare "i"
    funcs[i] = function() {
        console.log("My value: " + i); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) { // we can use "var" here without issue
    funcs[j]();
}

それがどれほど簡単か見てください!詳細については、私の情報が基づいているこの回答を参照してください。

于 2015-04-10T09:57:07.557 に答える
164

ES6 が広くサポートされるようになったため、この質問に対する最良の答えが変わりました。ES6 は、この正確な状況に対してletandconstキーワードを提供します。クロージャーをいじる代わりに、次のletようにループスコープ変数を設定するために使用できます。

var funcs = [];

for (let i = 0; i < 3; i++) {          
    funcs[i] = function() {            
      console.log("My value: " + i); 
    };
}

val次に、ループの特定のターンに固有のオブジェクトを指し、追加のクロージャー表記なしで正しい値を返します。これにより、明らかにこの問題が大幅に単純化されます。

constに似てletいますが、最初の代入後に変数名を新しい参照に再バインドできないという追加の制限があります。

最新バージョンのブラウザを対象とするブラウザのサポートが開始されました。const/let現在、最新の Firefox、Safari、Edge、および Chrome でサポートされています。Nodeでもサポートされており、Babelなどのビルドツールを活用すればどこでも使えます。ここで実際の例を見ることができます: http://jsfiddle.net/ben336/rbU4t/2/

ドキュメントはこちら:

ただし、Edge 14 より前の IE9-IE11 と Edge はサポートされていますが、上記が間違っていることに注意してください (それらは毎回let新しいものを作成しないため、上記のすべての関数は を使用した場合と同様に 3 をログに記録します)。Edge 14 はついにそれを正しくします。ivar

于 2013-05-21T03:04:48.667 に答える
94

別の言い方をすればi、関数内の は、関数の作成時ではなく、関数の実行時にバインドされるということです。

クロージャーを作成すると、クロージャーを作成したときiのコピーではなく、外側のスコープで定義された変数への参照になります。実行時に評価されます。

他の回答のほとんどは、値を変更しない別の変数を作成することで回避する方法を提供します。

わかりやすくするために説明を追加すると思いました。解決策については、個人的には、ここでの回答からそれを行う最も自明な方法であるため、Harto's を使用します。投稿されたコードはどれも機能しますが、新しい変数を宣言する理由 (Freddy と 1800 年代) や奇妙な組み込みクロージャー構文 (apphacker) を使用する理由を説明するコメントの山を書くよりも、クロージャー ファクトリを選択します。

于 2009-04-15T06:48:43.727 に答える
77

理解する必要があるのは、javascriptの変数のスコープが関数に基づいていることです。これは、ブロックスコープがあるc#と言うのとは重要な違いであり、変数をfor内の変数にコピーするだけで機能します。

変数が関数スコープを持っているので、apphackerの答えのように関数を返すことを評価する関数でそれをラップすることはトリックを行います。

varの代わりにletキーワードもあり、ブロックスコープルールを使用できます。その場合、for内で変数を定義するとうまくいきます。とはいえ、letキーワードは互換性があるため、実用的なソリューションではありません。

var funcs = {};

for (var i = 0; i < 3; i++) {
  let index = i; //add this
  funcs[i] = function() {
    console.log("My value: " + index); //change to the copy
  };
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}

于 2009-04-15T06:25:08.790 に答える
64

Bjorn の (apphacker) に似た手法の別のバリエーションを次に示します。これにより、変数値をパラメーターとして渡すのではなく、関数内で割り当てることができます。

var funcs = [];
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() {
        var index = i;
        return function() {
            console.log("My value: " + index);
        }
    })();
}

どの手法を使用しても、index変数は一種の静的変数になり、内部関数の返されたコピーにバインドされることに注意してください。つまり、その値の変更は呼び出し間で保持されます。とても便利です。

于 2012-08-07T08:45:35.700 に答える
62

これは、JavaScript でクロージャーを使用する際のよくある間違いについて説明しています。

関数は新しい環境を定義します

検討:

function makeCounter()
{
  var obj = {counter: 0};
  return {
    inc: function(){obj.counter ++;},
    get: function(){return obj.counter;}
  };
}

counter1 = makeCounter();
counter2 = makeCounter();

counter1.inc();

alert(counter1.get()); // returns 1
alert(counter2.get()); // returns 0

makeCounterForが呼び出されるたび{counter: 0}に、新しいオブジェクトが作成されます。obj また、新しいオブジェクトを参照するために、 の新しいコピーも作成されます。したがって、counter1counter2は互いに独立しています。

ループでの閉鎖

ループでクロージャーを使用するのは難しいです。

検討:

var counters = [];

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = {
      inc: function(){obj.counter++;},
      get: function(){return obj.counter;}
    }; 
  }
}

makeCounters(2);

counters[0].inc();

alert(counters[0].get()); // returns 1
alert(counters[1].get()); // returns 1

counters[0]counters[1]は独立していないことに注意してください。実際、それらは同じ上で動作しobjます!

objこれは、おそらくパフォーマンス上の理由から、ループのすべての繰り返しで sharedのコピーが 1 つしかないためです。{counter: 0}反復ごとに新しいオブジェクトを作成しますが、同じコピーが最新objのオブジェクトへの参照で更新されます。

解決策は、別のヘルパー関数を使用することです。

function makeHelper(obj)
{
  return {
    inc: function(){obj.counter++;},
    get: function(){return obj.counter;}
  }; 
}

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = makeHelper(obj);
  }
}

これが機能するのは、関数スコープ内のローカル変数と、関数の引数変数がエントリ時に新しいコピーに直接割り当てられるためです。

于 2013-04-20T09:59:57.620 に答える
34

これを使用する簡単なソリューションを次に示しますforEach(IE9まで機能します):

var funcs = [];
[0,1,2].forEach(function(i) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
})
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

版画:

My value: 0
My value: 1
My value: 2
于 2014-05-03T03:42:57.677 に答える
15

さまざまなソリューションを読んだ後、これらのソリューションが機能する理由は、スコープ チェーンの概念に依存していることを付け加えたいと思います。これは、JavaScript が実行中に変数を解決する方法です。

  • var各関数定義は、およびそのによって宣言されたすべてのローカル変数で構成されるスコープを形成しますarguments
  • 別の (外部) 関数内で定義された内部関数がある場合、これはチェーンを形成し、実行中に使用されます。
  • 関数が実行されると、ランタイムはスコープ チェーンを検索して変数を評価します。チェーンの特定のポイントで変数が見つかると、検索を停止して使用します。それ以外の場合は、に属するグローバル スコープに到達するまで続行しwindowます。

最初のコードでは:

funcs = {};
for (var i = 0; i < 3; i++) {         
  funcs[i] = function inner() {        // function inner's scope contains nothing
    console.log("My value: " + i);    
  };
}
console.log(window.i)                  // test value 'i', print 3

gets が実行されるとfuncs、スコープ チェーンは になりますfunction inner -> global。変数iが で見つからないfunction inner(使用して宣言されていないか、引数として渡されていない) ため、最終的にvarの値が であるグローバル スコープで見つかるまで検索を続けます。iwindow.i

外部関数でラップすることにより、hartoが行ったようにヘルパー関数を明示的に定義するか、 Bjornが行ったように無名関数を使用します。

funcs = {};
function outer(i) {              // function outer's scope contains 'i'
  return function inner() {      // function inner, closure created
   console.log("My value: " + i);
  };
}
for (var i = 0; i < 3; i++) {
  funcs[i] = outer(i);
}
console.log(window.i)          // print 3 still

gets が実行されるとfuncs、スコープ チェーンは になりますfunction inner -> function outer。この時間iは、for ループで 3 回実行される外部関数のスコープで見つけることができ、毎回値iが正しくバインドされます。window.i内部実行時の値は使用しません。

詳細については、ここを参照してください。これには、ここ
にあるようなループでクロージャを作成する際のよくある間違いと、クロージャが必要な理由とパフォーマンスの考慮事項が含まれています。

于 2014-07-14T14:42:00.293 に答える
10

forEachローカル変数の使用を (再) 回避するために関数を使用することを提案した人がまだ誰もいないことに驚いています。実際、私はfor(var i ...)この理由でもうまったく使用していません。

[0,2,3].forEach(function(i){ console.log('My value:', i); });
// My value: 0
// My value: 2
// My value: 3

forEach//マップの代わりに使用するように編集。

于 2014-12-09T22:24:17.963 に答える
9

元の例が機能しなかった理由は、ループで作成したすべてのクロージャが同じフレームを参照していたためです。i実際には、1つの変数だけで1つのオブジェクトに3つのメソッドがあります。それらはすべて同じ値を出力しました。

于 2009-04-15T06:18:29.510 に答える
8

まず、このコードの何が問題なのかを理解してください。

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

ここで、funcs[]配列が初期化iされ、インクリメントされると、funcs配列が初期化され、配列のサイズfuncが 3 になるので、i = 3,. が呼び出されると、すでに 3 にインクリメントされているfuncs[j]()変数 が再び使用されます。i

これを解決するために、多くのオプションがあります。以下にその 2 つを示します。

  1. で初期化iするletか、 で新しい変数indexを初期化しletて、 と等しくすることができますi。したがって、呼び出しが行われると、indexが使用され、そのスコープは初期化後に終了します。そして呼び出すために、index再び初期化されます:

    var funcs = [];
    for (var i = 0; i < 3; i++) {          
        let index = i;
        funcs[i] = function() {            
            console.log("My value: " + index); 
        };
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }
    
  2. その他のオプションtempFuncは、実際の関数を返すa を導入することです。

    var funcs = [];
    function tempFunc(i){
        return function(){
            console.log("My value: " + i);
        };
    }
    for (var i = 0; i < 3; i++) {  
        funcs[i] = tempFunc(i);                                     
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }
    
于 2016-11-04T07:46:07.800 に答える
4

さらに別の解決策: 別のループを作成する代わりに、単にthisreturn 関数にバインドします。

var funcs = [];

function createFunc(i) {
  return function() {
    console.log('My value: ' + i); //log value of i.
  }.call(this);
}

for (var i = 1; i <= 5; i++) {  //5 functions
  funcs[i] = createFunc(i);     // call createFunc() i=5 times
}

これをバインドすることで、問題も解決します。

于 2016-05-05T11:48:51.130 に答える
4

forEach疑似範囲を作成する独自のクロージャーを持つ関数を使用することを好みます。

var funcs = [];

new Array(3).fill(0).forEach(function (_, i) { // creating a range
    funcs[i] = function() {            
        // now i is safely incapsulated 
        console.log("My value: " + i);
    };
});

for (var j = 0; j < 3; j++) {
    funcs[j](); // 0, 1, 2
}

それは他の言語の範囲よりも醜く見えますが、私見は他のソリューションよりも怪物ではありません。

于 2015-12-17T14:14:56.857 に答える
4

query-js (*)などのデータのリストには、宣言型モジュールを使用できます。このような状況では、個人的には宣言型アプローチの方が驚くほどではないと思います

var funcs = Query.range(0,3).each(function(i){
     return  function() {
        console.log("My value: " + i);
    };
});

次に、2番目のループを使用して、期待される結果を取得するか、または行うことができます

funcs.iterate(function(f){ f(); });

(*) 私は query-js の作成者であり、そのため、それを使用することに偏っています。そのため、私の言葉を、宣言型アプローチのためだけに上記のライブラリを推奨するものと見なさないでください :)

于 2015-06-17T12:02:42.773 に答える
3

コードは次のように機能するため、機能しません。

Create variable `funcs` and assign it an empty array;  
Loop from 0 up until it is less than 3 and assign it to variable `i`;
    Push to variable `funcs` next function:  
        // Only push (save), but don't execute
        **Write to console current value of variable `i`;**

// First loop has ended, i = 3;

Loop from 0 up until it is less than 3 and assign it to variable `j`;
    Call `j`-th function from variable `funcs`:  
        **Write to console current value of variable `i`;**  
        // Ask yourself NOW! What is the value of i?

i問題は、関数が呼び出されたときの変数の値は何ですか? 最初のループは の条件で作成されているためi < 3、条件が false の場合はすぐに停止するので、 ですi = 3

関数が作成された時点では、そのコードは実行されず、後で使用するために保存されるだけであることを理解する必要があります。そのため、それらが後で呼び出されると、インタープリターはそれらを実行し、「の現在の値はi?」と尋ねます。

したがって、あなたの目標は、最初に の値iを関数に保存し、その後で関数を に保存することfuncsです。これは、たとえば次のように行うことができます。

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function(x) {            // and store them in funcs
        console.log("My value: " + x); // each should log its value.
    }.bind(null, i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

このように、各関数には独自の変数があり、これを各反復での値にx設定します。xi

これは、この問題を解決するための複数の方法の 1 つにすぎません。

于 2016-11-04T08:58:29.117 に答える
2

これは非同期コードでよく発生する問題です。変数iは変更可能であり、関数呼び出しが行われる時点で、使用iするコードが実行されi、最後の値に変更されます。したがって、ループ内で作成されたすべての関数が作成されます。クロージャーであり、 3 (ループiの上限 + 1) に等しくなります。for

iこれに対する回避策は、各反復の値を保持し、コピーを強制する関数を作成することiです (これはプリミティブであるため、役立つ場合はスナップショットと考えてください)。

于 2015-05-06T22:33:08.577 に答える
0

es6 を使用していないとしましょう。IFFY 関数を使用できます。

var funcs = [];
for (var i = 0; i < 13; i++) {      
funcs[i] = (function(x) {
console.log("My value: " + i)})(i);}

しかし、それは異なります。

于 2018-03-14T06:19:14.140 に答える
0

この質問は古くて答えがありますが、私はさらに別のかなり興味深い解決策を持っています:

var funcs = [];

for (var i = 0; i < 3; i++) {     
  funcs[i] = function() {          
    console.log("My value: " + i); 
 };
}

for (var i = 0; i < 3; i++) {
  funcs[i]();
}

変更は非常に小さいため、私が何をしたかを確認するのはほとんど困難です。2 番目のイテレータを aj から i に切り替えました。これにより、何らかの方法で i の状態が時間内に更新され、目的の結果が得られます。私は偶然にこれを行いましたが、以前の回答を考えると理にかなっています。

この小さな、しかし非常に重要な違いを指摘するためにこれを書きました。私のような他の学習者の混乱を解消するのに役立つことを願っています.

注:正しい答えだと思うので、これを共有していません。これは、特定の状況下で壊れる可能性が高い不安定なソリューションです。実際、それが本当にうまくいくことに私はかなり驚いています。

于 2018-02-25T03:15:21.233 に答える