البرمجة الوصفية في JavaScript: Proxy وReflect وSymbol

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

البرمجة الوصفية في JavaScript: عندما يكتب الكود نفسه بنفسه

\n\n

تخيل أنك تكتب برنامجًا قادرًا على تحليل وتعديل سلوكه الخاص أثناء التنفيذ. هل يبدو هذا كخيال علمي؟ مرحبًا بك في عالم البرمجة الوصفية في JavaScript!

\n\n

تتيح هذه التقنية للمطور تجاوز حدود الكود التقليدي والتحكم في بنية الكائنات نفسها، واعتراض استدعاءات الدوال، وحتى إنشاء خصائص افتراضية غير موجودة في الذاكرة. في هذه المقالة، سنشرح الركائز الثلاث للبرمجة الوصفية: Proxy وReflect وSymbol. ستتعلم كيفية استخدامها لبناء واجهات برمجية ذكية، وتنفيذ الحسابات البطيئة (lazy evaluation)، وحماية البيانات من التعديلات غير المقصودة.

\n\n

إذا كنت قد أتقنت أساسيات JavaScript وتريد الانتقال إلى المستوى التالي، فهذا المحتوى مناسب لك. لن نضيع الوقت في الأساسيات؛ بل سننتقل مباشرة إلى التقنيات المتقدمة مع أمثلة عملية.

\n\n

ما هي البرمجة الوصفية ولماذا نحتاجها؟

\n\n

في البرمجة التقليدية، نكتب كودًا يتعامل مع البيانات. أما في البرمجة الوصفية، فنكتب كودًا يتعامل مع كود آخر أو بنية الكائنات. وهذا يمنحنا إمكانيات مذهلة:

\n\n
    \n
  • التحقق من الصحة والأمان — التحقق تلقائيًا من القيم التي يتم تعيينها للخصائص.
  • \n
  • تسجيل الأحداث وتصحيح الأخطاء — اعتراض أي عملية على الكائن وعرضها في وحدة التحكم.
  • \n
  • الخصائص الافتراضية — إنشاء خصائص تُحسب فوريًا دون شغل مساحة في الذاكرة.
  • \n
  • إنشاء لغات خاصة بالمجال (DSL) — بناء سلاسل استدعاءات مثل jQuery أو Vue.
  • \n
\n\n

توفر JavaScript ثلاث أدوات قوية لتحقيق ذلك. دعنا نشرح كلًا منها.

\n\n

Proxy: جاسوسك الشخصي في عالم الكائنات

\n\n

Proxy هو كائن غلاف (wrapper) يتيح اعتراض وتعديل العمليات الأساسية على كائن آخر (الكائن الهدف). يمكنك "التنصت" على قراءة الخصائص، الكتابة، الحذف، استدعاء الدوال، وحتى التحقق من وجود خاصية باستخدام العامل in.

\n\n

الصيغة بسيطة: new Proxy(target, handler)، حيث handler هو كائن يحتوي على دوال المصيدة (traps).

\n\n

مثال 1: التحقق من صحة البيانات باستخدام Proxy

\n\n

لنفترض أن لدينا كائن مستخدم، ونريد أن يكون العمر رقمًا صحيحًا بين 0 و120، والاسم سلسلة نصية غير فارغة. بدون Proxy، كنا سنحتاج إلى كتابة دوال getter وsetter لكل حقل. مع Proxy، يتم ذلك بأناقة:

\n\n
const user = {\n    name: 'أحمد',\n    age: 25\n};\n\nconst validator = {\n    set(target, property, value) {\n        if (property === 'age') {\n            if (!Number.isInteger(value)) {\n                throw new TypeError('العمر يجب أن يكون رقمًا صحيحًا');\n            }\n            if (value < 0 || value > 120) {\n                throw new RangeError('العمر خارج النطاق المسموح');\n            }\n        }\n        if (property === 'name') {\n            if (typeof value !== 'string' || value.trim().length === 0) {\n                throw new TypeError('الاسم يجب أن يكون سلسلة نصية غير فارغة');\n            }\n        }\n        // إذا كان كل شيء صحيحًا، احفظ القيمة\n        target[property] = value;\n        return true; // أبلغ أن العملية نجحت\n    }\n};\n\nconst proxiedUser = new Proxy(user, validator);\n\n// اختبار\nproxiedUser.age = 30; // صحيح\nconsole.log(proxiedUser.age); // 30\n\nproxiedUser.age = -5; // خطأ: RangeError\nproxiedUser.name = ''; // خطأ: TypeError
\n\n

لاحظ أننا اعترضنا عملية التعيين وأضفنا منطقنا الخاص. هذا هو البرمجة الوصفية في JavaScript بشكلها النقي — كود يتحكم في سلوك كود آخر.

\n\n

مثال 2: الحسابات البطيئة والخصائص الافتراضية

\n\n

تخيل أن لدينا

المدونات

توصيات الكتب