5

Eloquent Javascriptでは、作成者は読者に関数を作成するように依頼します。この関数は、数値の配列を引数として取り、 reduce関数countZeroesを使用する別の例としてその中で発生するゼロの量を返します。

知っている

  • reduce関数の概念は、配列を取得して単一の値に変換することです。
  • 関数の本質的な部分である三項演算子が行っていること。

知らない

  • ここで、counter関数の引数はから来ています。

本から:

function countZeroes(array) {
  function counter(total, element) { // Where are the parameter values coming from?
    return total + (element === 0 ? 1 : 0);
  }
  return reduce(counter, 0, array);
}

テキストからの以前の例:

function reduce(combine, base, array) {
 forEach(array, function (element) {
    base = combine(base, element);
  });
  return base;
}
4

3 に答える 3

8

関数は、コードの最初のブロックで呼び出されたときcounterの最初のパラメーターとして渡されます。reduce関数内ではreduce、最初のパラメーターはとして知られていcombineます。次に、これはパラメーターbaseを使用して呼び出されますelement。これは、探している不思議な引数です。

したがって、注意が必要なのは、関数が定義されて名前が付けられている場所では実行されず、reduce関数にパラメーターとして渡されてから実行されることです。

編集:詳細

ロジックフロー

つまり...関数が定義されて名前が付けられ(ポイント1)、定義が渡されます。名前は付けられずに、別の関数(ポイント2)と変数(私はiとiiと呼びます)に渡され、そこで次の名前が取得されます。他のパラメーターと一緒に呼び出される前の最初のパラメーター(ポイント3)(ポイント4)

編集:さらなる詳細

配列からの要素をよりよく説明するために、画像を更新しました。

そのため、関数が呼び出されたときのように作成され、名前がパラメーターとして割り当てられてから、/関数の結果として再割り当てされ、可能な増分でが返されるiため、追跡が容易になります。0reducebasecountercombinebase

iiに渡された配列としてライフを開始し、ループcountZeroesによって繰り返されるまでチェーンに沿って渡されforEachます。ループは、単一を抽出し、その上で関数を(とともに)element操作します。combinebase

于 2012-11-02T21:54:58.270 に答える
7

コードを見ると、考えられる答えは1つだけです。関数counterはに渡されたときに一度だけ参照されるためreduce()、reduceは関数に引数を提供する必要があります。

削減の仕組み

これは、reduceがどのように機能するかを視覚化したものです。ダイアグロムを上から下に読み、/どのパラメーター(下)が上の関数\に渡されるかを示す必要があります。counter()

                   return value of reduce()
                   /
                 etc ...
                /
            counter
           /       \
       counter      xs[2]
      /       \
  counter      xs[1]
 /       \
0         xs[0]

counter()最初に0(結局のところ、要素をまだ処理していないときに見られるゼロの初期の合計量はちょうどゼロです)、最初の要素が提供されます。

0配列の最初の要素がゼロの場合、これは1ずつ増加します。最初の要素を見た後の新しい合計はcounter(0, xs[0])reduce()関数に返されます。要素が残っている限り、この値を新しい保留中の合計としてcounter()、配列の次の要素とともに関数に渡しますxs[1]

配列に要素がある限り、このプロセスが繰り返されます。

この概念をコードにマッピングする

function reduce(combine, base, array) {
 forEach(array, function (element) {
    base = combine(base, element);
  });
  return base;
}

図からわかるように、は、構造内の最初の「反復」を示すとともに、最初に関数に0渡されます。結果の値は、に書き戻されます。baseelementxs[0]forEachbase

視覚化でわかるように、0は関数の左パラメーターでcounter()あり、その結果は左パラメーターとしてに渡されますcounter()base/totalコンストラクト内で左側のパラメーターとして機能するためforEach、その値をに書き戻すのは理にかなっています。base/totalそのため、前の結果はcounter()/combine()次の反復で再び渡されます。sのパス/は、の「フロー」ですbase/total

どこelementから来たの

Eloquent JavaScriptの第6章から、次の実装がありますforEach()(コメントでは、への呼び出しをaction最終的な値に置き換えました)。

function forEach(array, action) {
  for (var i = 0; i < array.length; i++)
    action(array[i]); // <-- READ AS: base = counter(base, array[i]);
}

actionforを繰り返しながら、すべての要素の単純なループ内で呼び出される関数を示しますarray

あなたの場合、これは次のように渡されactionますforEach()

function (element) {
    base = combine(base, element);
}

これは、への各呼び出しで定義された匿名関数reduce()です。したがって、の反復ごとにelement「本当に」 1回です。array[i]for

于 2012-11-02T22:03:26.363 に答える
1

このreduceメソッドはパラメータを渡します。関数のソースコードのどこかに、reduceおそらく次のようなものがあります。

function reduce(iterator, memo, collection) { // in your example, iterator here is your counter function
    …
    // while looping through the collection you passed in
    memo = iterator(memo, collection[i], i); // it calls your counter function and
                                             // passes the total and the current array
                                             // element as well as the current index,
                                             // then stores the result to be passed in
                                             // with the next array element
    …
    return memo;
}

補遺

多分これはよりよく説明するのに役立ちます(jsfiddle):

// very simple reduce implementation
function reduce(iterator, memo, collection) {
    for (var i = 0; i < collection.length; i++) {
        memo = iterator(memo, collection[i], i);
    }
    return memo;
}

zeroes = [1,0,0,1,1,0,1];
function counter(total, element) { return total + (element === 0 ? 1 : 0); }

alert(reduce(counter, 0, zeroes));
于 2012-11-02T22:02:43.227 に答える