以下は John Hann の実装からのもので、このコードはメソッド呼び出しの結果をキャッシュする賢い方法を使用しています。
コード分析:
// memoize: メモ化を使用したキャッシュの一般的な方法
// func: キャッシュされるメソッド
// コンテキスト: メソッド実行コンテキスト
// 注: メソッドは外部からアクセス可能であり、パラメーターは文字シリアル化可能である必要があります
function memoize (func, context) {
Function memoizeArg (argPos) { //パラメータは元のメソッド内のパラメータの位置を示します
var queue = {} //このキャッシュのキーはパラメータ、値は実行結果です
return function () { //関数クロージャを返します
If (argPos == 0) { //最初のパラメータ、キャッシュされたキーにパラメータが存在しない場合は、元の関数を実行し、実行結果を保存します
If (!(キャッシュ内の引数[argPos])) {
キャッシュ[引数[argPos]] = func.apply(コンテキスト, 引数);
return キャッシュ[引数[argPos]];
Else {// が最初のパラメータではない場合、パラメータがキャッシュ キーに存在しない場合は、元のメソッド 1
内のパラメータの位置が再帰的に実行されます。
If (!(キャッシュ内の引数[argPos])) {
キャッシュ[引数[argPos]] = memoizeArg(argPos - 1);
return queue[arguments[argPos]].apply(this, argument);
}
}
var arity = func.arity || func.length; // func パラメータの長さ、length 属性は JavaScript で使用され、arity 属性はその他で使用されます
Return memoizeArg(arity - 1) //最後のパラメータから再帰
}
使用:
コードをコピー
コードは次のとおりです:
var mem = memoize(func, this);
アラート(mem.call(this,1,1,2));
アラート(mem.call(this,2,1,2));
アラート(mem.call(this,3,1,3));
alert(mem.call(this,2,2,4));
単純なように見えますが、一見すると理解するのは簡単ではないかもしれませんが、クロージャの使用に慣れていれば、簡単に理解できるでしょう。上記の mem.call へのいくつかの呼び出しの後、ツリーが形成されます。各ノードはクロージャであり、各クロージャにはキャッシュがあり、各キャッシュのキーはツリー ブランチです。
(注: 上の図の「結果」もクロージャですが、argPos は 0 です)
しかし、方法はたくさんあります。たとえば、リンボーイは次のように言いました。
コードをコピー
コードは次のとおりです:
function Memoize(fn){
var キャッシュ = {};
戻り関数(){
var key = [];
for( var i=0, l = argument.length; i
key.push(arguments[i]);
If( !(キャッシュ内のキー) )
キャッシュ[キー] = fn.apply(this, argument);
キャッシュを返す
};
}
実装はより単純ですが、パラメーターを配列にプッシュし、その配列をキーとして使用します。キーは文字列型のみをサポートするため、使用するときはこれに注意する必要があります (たとえば、オブジェクトtostring "[object Object]" の後にのみ表示されます)、その機能は上記のものよりも弱いです。
これを改善するのは難しくありません。パラメータ用に別のオブジェクトを作成するだけで、元のキャッシュ オブジェクトとこの別のパラメータ オブジェクトが ID に関連付けられます。
コードをコピーします
コードは次のとおりです:
function Memoize(fn){
var キャッシュ = {}、引数 = {};
戻り関数(){
for( var i=0, key = args.length; i
If( 等しい( args[i], 引数 ) )
キャッシュを返す
}
args[キー] = 引数;
キャッシュ[キー] = fn.apply(this, argument);
キャッシュを返す
};
}
簡潔な関数メソッドとして記述できるメソッドは他にもあります。