فيما يلي من تطبيق John Hann ، وقد لفتت انتباهي هذا الرمز ، والذي قام بالتخزين المؤقت لنتيجة استدعاء الطريقة بطرق ذكية.
تحليل الكود:
نسخة الكود كما يلي:
// Memoize: طريقة شائعة لاستخدام المذكرة لذاكرة التخزين المؤقت
// func: طريقة يتم تخزينها مؤقتًا
// السياق: سياق تنفيذ الطريقة
// ملاحظة: يجب أن تكون الطريقة متاحة خارجيًا ، والمعلمات محددة
مذكرات الوظيفة (func ، السياق) {
الدالة memoizearg (argpos) {// تشير المعلمة إلى موضع المعلمة في الطريقة الأصلية
var cache = {} ؛ // مفتاح هذه التخزين المؤقت هو المعلمة ، والقيمة هي نتيجة التنفيذ
Return Function () {// إرجاع إغلاق الوظيفة
إذا (argpos == 0) {// المعلمة الأولى ، إذا لم تكن المعلمة موجودة في المفتاح المخطط ، فسيتم تنفيذ الوظيفة الأصلية وسيتم تخزين نتيجة التنفيذ
if (! (الوسائط [argpos] في ذاكرة التخزين المؤقت)) {
ذاكرة التخزين المؤقت [وسيطات [argpos]] = funC.Apply (السياق ، الوسائط) ؛
}
إرجاع ذاكرة التخزين المؤقت [الوسائط [argpos]] ؛
}
آخر {// ليس المعلمة الأولى. إذا لم تكن المعلمة موجودة في المفتاح المخزنة مؤقتًا ، فسيتم تنفيذ طريقة MemoizeArg بشكل متكرر. موضع المعلمة في الطريقة الأصلية -1
if (! (الوسائط [argpos] في ذاكرة التخزين المؤقت)) {
ذاكرة التخزين المؤقت [وسيطات [argpos]] = memoizearg (argpos - 1) ؛
}
إرجاع ذاكرة التخزين المؤقت [وسيطات [argpos]]. تطبيق (هذا ، الحجج) ؛
}
}
}
var arity = func.arity || func.length ؛ // يتم استخدام طول معلمة FUNC ، ويتم استخدام سمة Arity في JavaScript.
إرجاع memoizearg (arity - 1) ؛ // يبدأ التراجع من المعلمة الأخيرة
}
يستخدم:
نسخة الكود كما يلي:
var mem = memoize (func ، هذا) ؛
ALERT (MEM.Call (هذا ، 1،1،2)) ؛
ALERT (mem.call (هذا ، 2،1،2)) ؛
ALERT (MEM.Call (هذا ، 3،1،3)) ؛
ALERT (MEM.Call (هذا ، 2،2،4)) ؛
يبدو الأمر بسيطًا ، لكن لا يبدو من السهل فهمه عندما تنظر إليه ، ولكن إذا كنت على دراية باستخدام عمليات الإغلاق ، فسيكون من السهل فهمه. بعد المكالمات أعلاه إلى mem.call ، تتشكل شجرة. كل عقدة عبارة عن إغلاق ، وكل إغلاق يحتوي على ذاكرة التخزين المؤقت ، وكل مفتاح ذاكرة التخزين المؤقت هو فرع شجرة:
(ملاحظة: "النتيجة" في الصورة أعلاه هي أيضًا إغلاق ، لكن Argpos هو 0 فقط)
ولكن هناك العديد من الطرق ، كما قال Limboy:
نسخة الكود كما يلي:
مذكرات الوظيفة (fn) {
var cache = {} ؛
وظيفة الإرجاع () {
VAR KEY = [] ؛
لـ (var i = 0 ، l = enduments.length ؛ i <l ؛ i ++)
key.push (الوسيطات [i]) ؛
إذا (! (مفتاح في ذاكرة التخزين المؤقت))
ذاكرة التخزين المؤقت [المفتاح] = fn.apply (هذا ، الوسائط) ؛
إرجاع ذاكرة التخزين المؤقت [المفتاح] ؛
} ؛
}
يكون التنفيذ أسهل ، ولكن ادفع المعلمات إلى صفيف ثم تعامل مع الصفيف كمفتاح ، والمفتاح يدعم نوع السلسلة فقط. لذلك ، تحتاج إلى الانتباه إلى هذه النقطة عند استخدامها (على سبيل المثال ، بعد كائن tostring ، قد ترى فقط "[كائن كائن]") ، ووظائفها أضعف من الواردة أعلاه.
ليس من الصعب تحسين هذا. فقط قم بإعداد كائن آخر بالمعلمة ، ويرتبط كائن ذاكرة التخزين المؤقت الأصلي وكائن المعلمة الآخر بالمعرف:
نسخة الكود كما يلي:
مذكرات الوظيفة (fn) {
var cache = {} ، args = {} ؛
وظيفة الإرجاع () {
لـ (var i = 0 ، key = args.length ؛ i <key ؛ i ++) {
إذا (متساوية (args [i] ، الحجج)))
إرجاع ذاكرة التخزين المؤقت [i] ؛
}
args [key] = الوسيطات ؛
ذاكرة التخزين المؤقت [المفتاح] = fn.apply (هذا ، الوسائط) ؛
إرجاع ذاكرة التخزين المؤقت [المفتاح] ؛
} ؛
}
هناك بعض الطرق الأخرى التي يمكن كتابتها كطرق وظيفية موجزة.