ต่อไปนี้มาจากการใช้งานของ 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, this);
การแจ้งเตือน (mem.call (นี่, 1,1,2));
การแจ้งเตือน (mem.call (นี่, 2,1,2));
การแจ้งเตือน (mem.call (นี่, 3,1,3));
การแจ้งเตือน (mem.call (นี่, 2,2,4));
ดูเหมือนง่าย แต่ดูเหมือนจะไม่เข้าใจง่ายเมื่อคุณดู แต่ถ้าคุณคุ้นเคยกับการใช้งานปิดมันจะเข้าใจง่าย หลังจากการเรียกข้างต้นไปยัง mem.call ต้นไม้จะถูกสร้างขึ้น แต่ละโหนดคือการปิดการปิดแต่ละครั้งจะมีแคชและแต่ละปุ่มแคชเป็นสาขาต้นไม้:
(หมายเหตุ: "ผลลัพธ์" ในภาพด้านบนก็เป็นการปิดตัวลงเช่นกัน แต่ Argpos เป็นเพียง 0)
แต่มีหลายวิธีเช่น Limboy กล่าวว่า:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นบันทึกความทรงจำ (FN) {
var cache = {};
return function () {
var key = [];
สำหรับ (var i = 0, l = arguments.length; i <l; i ++)
key.push (อาร์กิวเมนต์ [i]);
ถ้า (! (กุญแจในแคช))
แคช [คีย์] = fn.apply (สิ่งนี้, อาร์กิวเมนต์);
ส่งคืนแคช [คีย์];
-
-
การใช้งานนั้นง่ายกว่า แต่ผลักดันพารามิเตอร์ลงในอาร์เรย์แล้วปฏิบัติกับอาร์เรย์เป็นคีย์และคีย์รองรับประเภทสตริงเท่านั้น ดังนั้นคุณต้องให้ความสนใจกับจุดนี้เมื่อใช้งาน (ตัวอย่างเช่นหลังจากวัตถุ toString คุณอาจเห็น "[Object Object]") และฟังก์ชั่นของมันจะอ่อนแอกว่าด้านบน
มันไม่ยากที่จะปรับปรุงสิ่งนี้ เพียงตั้งค่าวัตถุอื่นด้วยพารามิเตอร์และวัตถุแคชดั้งเดิมและวัตถุพารามิเตอร์อื่น ๆ นี้เชื่อมโยงกับ ID:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นบันทึกความทรงจำ (FN) {
var cache = {}, args = {};
return function () {
สำหรับ (var i = 0, key = args.length; i <key; i ++) {
ถ้า (เท่ากัน (args [i], อาร์กิวเมนต์))
คืนแคช [i];
-
args [key] = อาร์กิวเมนต์;
แคช [คีย์] = fn.apply (สิ่งนี้, อาร์กิวเมนต์);
ส่งคืนแคช [คีย์];
-
-
มีวิธีการอื่นที่สามารถเขียนเป็นวิธีการทำงานที่กระชับ