مستوى القارئ: متوسط — تحتاج فهم سابق لـ objects و functions في JavaScript، وفكرة عامة عن getter/setter.
الـ Proxy في JavaScript مش feature تستعرض بيها في مقابلة. هو الحل الوحيد لما تحتاج تراقب أو تتحكم في أي عملية على object بدون ما تعدّل الكود اللي بيستخدمه. لو جربت قبل كده تستخدم getter/setter وحسّيت إن لازم تعرف اسم كل property مقدمًا، الـ Proxy هو اللي بيكسر القيد ده.
JavaScript Proxy: الاعتراض قبل الوصول للـ Object
المشكلة باختصار
تخيل إن عندك object بيتغيّر من 12 مكان مختلف في الكود. يوم واحد بتلاقي قيمة غريبة فيه، ومش عارف مين كتبها. الحل التقليدي: تروح كل مكان، تضيف console.log، تجرّب، وترجع تشيلهم. ده شغل أيام.
الـ Proxy بيخليك تعمل نفس المراقبة في 5 سطور، من غير ما تلمس أي ملف من الـ 12 ده. أكتر من كده، يقدر يرفض أي قيمة غلط قبل ما توصل للـ object أصلاً.
اشرحلي بمثال بسيط الأول
تخيل سكرتير في مكتب مدير. أي حد عايز يكلم المدير، لازم يعدّي على السكرتير. السكرتير يقدر:
- يقول "المدير مش موجود" بدل ما يدخّل الزائر.
- يسجّل اسم كل زائر ووقت الزيارة.
- يرفض الزائر لو ملوش موعد.
- يعدّل رسالة الزائر قبل ما توصل.
المدير نفسه مش لازم يعرف إن في سكرتير، ومش لازم يغيّر شغله. الـ Proxy في JavaScript بيلعب دور السكرتير ده مع object.
التعريف العلمي بدقة
الـ Proxy هو object بيلف object تاني (اسمه target)، ومعاه object تاني فيه دوال اسمها traps (اسمه handler). كل trap بيعترض عملية أساسية محددة من الـ internal methods اللي JavaScript بيستخدمها على objects.
المواصفة الرسمية في ECMAScript بتعرّف 13 trap. أكترهم استخدامًا: get, set, has, deleteProperty, apply, construct, ownKeys. أي عملية ما تعرّفش لها trap، بترجع بشكل افتراضي للـ target من غير تدخّل.
أبسط Proxy ممكن تكتبه
const user = { name: "أحمد", age: 30 };
const tracked = new Proxy(user, {
get(target, prop) {
console.log(`قراءة: ${String(prop)}`);
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log(`كتابة: ${String(prop)} = ${value}`);
return Reflect.set(target, prop, value);
}
});
tracked.name; // قراءة: name
tracked.age = 31; // كتابة: age = 31
console.log(user.age); // 31 — التغيير وصل للـ target الأصلي