JavaScriptのメモリ機能を作成する


私がこれまでに知った最初のソフトウェア開発コースのうちの1つは、ゼロからよく知られているJavaScriptライブラリUnderscore.jsを再現することに関係しました.
それぞれのマップやマップのようなもっと基本的なものを実装することは私にとって管理可能でしたが、より進んだものに到達したとき、私は維持できませんでした.本当に私に多くのトラブルを与えた機能の1つは、memoizeでした.私は、私の同僚のうちの1人がちょうどそれをする方法を私に見せなければならなかったまで、数時間の間この機能で私の頭を壁にぶつけました.私は間違いなくそれを考えていました、そして、私の同輩がどのように働いたかについて説明した後でさえ、私は完全にそれを理解しませんでした.
反応を学んで、より多くのアルゴリズム機能を研究している間、回想概念に遭遇した後に、私は概念と実行を理解しているように、メモ機能を感じて、感じます.

何を覚えているときに使用する必要がありますか?
アンダースコア文書によると

Memoizes a given function by caching the computed result. Useful for speeding up slow-running computations.


memoize関数は引数として機能します.memoize関数を返します.memoize関数(memoizeに最初に渡された関数)が呼び出されたとき、memoizeは関数が既に特定の引数集合で呼び出されたかどうかを調べます.もしそうならば、memoizeはそのキャッシュに格納されるその計算の結果を既に持ちます.それで、それはそれを見て、すでに計算された結果を返します.memoizedされた関数が特定のセットの引数でまだ呼ばれていないならば、memoizeは計算を実行して、結果をそのキャッシュに格納して、結果を返すでしょう.
なぜそれを使用する?あなたがプログラムに頻繁に使用されることは本当に“高価な”機能を持っていると言う.代わりに何度もそれを呼び出すと、memoizeでは、特定の計算の結果を保存することができます.したがって、関数が同じ引数の引数を1回以上呼び出すと、計算を繰り返す必要はありません.

警告と先取特権

  • 文法.ES 6構文をすべて使いますので、すべての関数は矢印関数となります.これは構文に加えて、このキーワードの実行コンテキストに関する含意を持ちます.私はrest parameterと対照的にarguments objectを使用するつもりです.そして、それは我々がJavaScriptのビルトイン配列メソッドをより効率的に使うのを許します.
  • 閉鎖.クロージャの私の好きな定義は、外側の関数が返された後でさえ、外側の関数のスコープ変数にアクセスできる内部関数です.これは私たちのmemoize機能を実装する際の鍵です.追加情報はMDN documentationにご相談ください.
  • 機能方法/適用.関数はJavaScriptの最初のクラスオブジェクトです.配列と同様に、プロトタイプメソッドがあります.適用は、関数の実行コンテキストを変更するために使用されます.これは、パラメータとしての関数、関数の戻り値、異なるスコープでの関数の使用を扱うので、私たちの実装にとって重要です.追加情報はMDN documentationにご相談ください.
  • プリミティブ対複雑なデータ型.この例の関数は文字列や数字などの原始データに対してのみ最適化されます.複雑なデータは参照によって通過されて、私たちが互いに「深く等しい」ことをチェックするロジックを実装するのを必要とするでしょう.JavaScriptのデータ型のレビューについては、MDN documentationに相談してください.

  • 私たちの記憶機能
    通常、私たちは、より複雑な機能のためにmemoizationテクニックを使用するでしょう、しかし、この例のために、我々は不特定の量の数をとる単純な加算機能を使用して、彼ら全員を一緒に加えます.
    const add = (...args) => {
      return args.reduce((s, e) => {
        return s += e;
      }, 0);
    }
    
    この関数は、残りのパラメータを使用して、すべての引数を配列に収集し、配列メソッドを使用してすべてを一緒に追加します.

    メモの実装
    まず、memoizeは、パラメータとして記憶したい関数を受け取ります.それから、我々は以前に計算された結果を保存するためにキャッシュを必要とします.値を調べる必要があるので、キー値のペアで何かを必要とします.それで、我々はオブジェクトリテラルとともに行きます.
    const memoize = func => {
      const cache = {};
    }  
    
    memoize指定しない量の引数を受け取る関数を返します.
    const memoize = func => {
      const cache = {};
      return (...args) => {
      }
    }
    
    memoizedされた関数が特定のセットのセットで呼ばれているか、またはキャッシュに計算を格納することができるキーを作成する方法を持っているなら、我々は見たいです.では引数を文字列にして関数スコープ変数に格納しましょう.
    const memoize = func => {
      const cache = {};
      return (...args) => {
         let strKey = args.join(',');
      }
    }
    
    我々は、我々が我々の次のステップであるルックアップまたは保管のために使うことができるストリングにすべての数を回すために、Joinメソッドを使用します.
    const memoize = func => {
      const cache = {};
      return (...args) => {
         let strKey = args.join(',');
         if(!cache[strKey]){
            cache[strKey] = func.apply(this, args);
          } 
           return cache[strKey];
       }
      }
    }
    
    if文では、memoized関数が呼び出されていないかどうかを確認します.その場合は、関数のプロトタイプメソッドを使用してキャッシュに格納して、新しいスコープでmemoized関数を呼び出します.外部関数が返された後に、グローバルスコープ内で既に動作しているとしても、クロージャのためキャッシュにアクセスできます.
    計算を実行して保存した後、内部関数はキャッシュから結果を返します.計算が既にキャッシュに格納されている場合、IFブロックはスキップされ、値が返されます.

    追記する
    以前から私たちのadd機能を使用して、記憶するために、これをすべてしましょう.
    const memoize = func => {
      const cache = {};
      return (...args) => {
      console.log(cache)
         let strKey = args.join(',');
          if(!cache[strKey]){
            console.log('adding to cache!');
            cache[strKey] = func.apply(this, args);
          } 
           console.log('fetching from cache!');
           return cache[strKey];
       }
    }
    
    const add = (...args) => {
      return args.reduce((s, e) => {
        return s += e;
      }, 0);
    }
    
    const memoizedAddFunction = memoize(add);
    
    memoizedAddFunction(1, 2, 3);
    memoizedAddFunction(1, 2, 3);
    memoizedAddFunction(4, 2, 3);
    memoizedAddFunction(4, 2, 3);
    memoizedAddFunction(8, 2, 3);
    memoizedAddFunction(1, 2, 3);
    memoizedAddFunction(4, 2, 3);
    memoizedAddFunction(8, 2, 3);
    
    そして、我々はそれを持っている!
    私はあなたの好みのJavaScript環境でこの関数を実行することを奨励し、いくつかのより多くの/別の数字でMemoizedAddfunctionのいくつかのより多くの呼び出しを追加します.私はいくつかのコンソールログをmemoizeで様々な場所に含まれているので、計算されたが追加されたり、キャッシュからフェッチを見ることができます.
    私は、これが私がブートキャンプで数ヶ月前私に多くのトラブルを与えた概念を明確にすることを願っています.あなたが記事が好きなら、私に、共有、またはコメントをください.あなたが本当にそれが好きならば、buying me a cup of coffee!によって私を助けてください