اذهب إلى المحتوى

كل الأنشطة

تحدث تلقائيًا

  1. الساعة الماضية
  2. لا يوجد ضرورة لاختيار باقة معينة من هوستنجر من أجل جعل الموقع جاهزا للتسويق الرقمي، و أكيد يمكن لأي موقع على هوستنجر أن يكون قابلا لعمليات التسويق الرقمي، و الأمر هنا ليس له علاقة بالإستضافة بل يكون بالتعديل على الكود الخاص بالموقع عن طريق إضافة أكواد التتبع الخاصة بالمواقع المعروفة.
  3. ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم الأسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
  4. بهذا الشكل اعتقد ان الكائن راح يطير اذا كنا معلقين على زر المسطرة وهذي راح تشكل مشكلة اعتقد الحل لهذي المشكلة اننا نحط جملة شرطية داخل جملة اذا ضغط زر المسافة بان نخلي y لا تزيد عن عدد معين ثم لا يمكن ضغط المسطرة حتى تكون اقل من هذا الحد
  5. السلام عليكم طلب احد العملاء ان اقوم برفع موقعه عل الانترنت باستخدام hostinger وسألني اذا ما سيكون الموقع جاهز لل digital marketing عند رفعه فهل بجب تحديد باقه معينه من hostinger من أجل هذا ؟
  6. اليوم
  7. السلام عليكم ممكن سؤال اني مشروع تخرجي كشف التسلل بالديب ليرنك واريد مساعده
  8. الأمر مماثل لاستضافة الموقع على حاسوبك، لكن تلك استضافة على الإنترنت متاحة للوصول من قبل الجميع وبها مواصفات مناسبة لحجم زوار الموقع المتوقع. ما يقصده هو إضافة أكواد Meta Pixel الخاصة بفيسبوك وأكواد التتبع الخاصة بتيك توك مثلاً وغيرهم مثل Google analytics. وذلك لا علاقة له بالاستضافة، أيضًا بالنسبة للـ SEO، فذلك يتوقف على جودة كود الموقع وتوافقه مع معايير الـ technical SEO.
  9. هوستنجر مجرد خدمة استضافة ولا علاقة لها بالتسويق الرقمي بصورة مباشرة، وبالبطع نعم، يمكن للموقع المستضاف على هوستنجر أن يكون قابلا لعمليات التسويق الرقمي. اذ ان توافر الخدمات التي تدعم استراتيجيات التسويق الرقمي مثل SEO والإعلانات على وسائل التواصل الاجتماعي والتحليلات الويب هي المهمة لضمان نجاح استراتيجيات التسويق الرقمي وليس نوع خدمة الاستضافة بشكل كبير. كما أن هوستنجر يوفر الكثير من الخدمات التنافسية التي تساعدك في الأمر، مثل تتبع حركة المرور عبر الموقع وما إلى ذلك ..
  10. السلام عليكم يريد عميل رفع موقع له عل hostinger ولم اقم بالتعامل علي hostinger من قبل وسألني هل عند رفع الموقع سيكون قابل لعمليه digital marketing ام لا هنا اي باقه اشتري من hostinger العميل يريد تجربه لمده شهر هل سيكون الموقع متاح للتسويق عند الرفع علي اي باقه ف hostinger ام لا
  11. عليك تحديد من هو المقصود بالمخطط؟ هل هو مخصص للمطورين أم للمستخدمين غير المتخصصين؟ فالأمر يعتمد على مستوى التفصيل المطلوب والغرض من المخطط، ففي حال كان المستوى عالٍ أي مُلخص، فاذكر فقط لقاعدة البيانات مثل "إضافة مستخدم" أو "حذف منتج" دون الخوض في التفاصيل الدقيقة. استخدام رموز محددة لتمثيل عمليات قاعدة البيانات الشائعة، مثل: ⊕ للإضافة ⊘ للحذف ≢ للتحديث ⊅ للاستعلام وفي حال كان المستوى تفصيلي، اذكر خطوات SQL إن كان من المهم توضيح الخطوات الدقيقة لعمليات قاعدة البيانات، وكتابة استعلامات SQL الفعلية داخل المخطط. مع ملاحظات لشرح تفاصيل عمليات قاعدة البيانات، مثل الجداول والأعمدة التي يتم التأثير عليها. وتستطيع إنشاء مخططات فرعية منفصلة لتمثيل عمليات قاعدة البيانات المعقدة، مع ربطها بالمخطط الرئيسي باستخدام أسهم أو تعليقات.
  12. عفوًا، سعيد بمساعدتك! فعلاً، الخوارزميات زي خوارزمية مشكلة الحقيبة (Knapsack Problem) ليها أهمية كبيرة في عالم الذكاء الاصطناعي وعلوم الحاسب بشكل عام لأسباب كتير منها ان الذكاء الاصطناعي بيشمل تطبيقات واسعة بتعتمد على حل مشكلات التحسين، ومشكلة الحقيبة دي من المشاكل الكلاسيكية اللي بتتطلب حلول ذكية. فهم خوارزميات زي البرمجة الديناميكية ممكن يساعد في تطوير حلول أكثر فعالية لمشكلات أصعب. وفي مجال تحليل البيانات والتعلم الآلي، كتير بيتطلب من الأنظمة انها تتخذ قرارات بتوزيع الموارد بشكل مثالي أو اختيار مجموعات بيانات معينة. خوارزميات زي خوارزمية الحقيبة ممكن تساعد في تحديد أي الميزات أو النماذج اللي بتعطي أحسن أداء مع محدوديات معينة. وايضا خوارزميات التحسين واتخاذ القرارات المعقدة بتتستخدم بشكل كبير في صناعة الألعاب وتطوير الروبوتات، حيث إن الذكاء الاصطناعي بيستخدم الخوارزميات دي لتقييم الخيارات المتاحة واختيار أفضل استراتيجية. ولا تنسي ان التعرف على الخوارزميات دي بيساعد على بناء فهم قوي للنظرية الحاسوبية والخوارزميات، وده بيساهم في تطوير مهارات حل المشكلات والتفكير النقدي في مجال الذكاء الاصطناعي. وعلى الرغم من إن خوارزمية مشكلة الحقيبة ممكن متتستخدمش مباشرة في كل تطبيقات الذكاء الاصطناعي، الفهم العميق لإزاي الخوارزميات بتتعامل مع المشكلات التحسينية بيعتبر جزء أساسي من تصميم الأنظمة الذكية.
  13. في الواجهة الأمامية يتم استخدام ESM والتي هي اختصار لـ ECMAScript modules، بينما في Node.js يتم استخدام نظام الوحدات modules باسم CommonJS. وستجد تفصيل عن ذلك هنا: لكن مؤخرًا كان هناك إتجاه إلى استخدام ESM أيضًا في Node.js، وستجد أن المكتبات الحديثة تدعم ذلك بشكل إفتراضي وتم التخلي عن CommonJS بها، وكان يجب القيام بخطوات بسيطة لكي تتمكن من استخدام ESM في Node.js مثل وضع خاصية type بقيمة module في ملف package.json. أو بشكل أبسط استخدام صيغة mjs. بدلاً من js. للملف الذي تريد به استخدام ESM. لكن لا حاجة إلى ذلك الآن، فقد دعم ذلك في إصدار 22 من Node.js وأصبح بإمكانك استخدام ESM بدون ما سبق، وذلك باستخدام require لكن ذلك لن يعمل في حال كانت الحزمة تستخدم top level await
  14. شكراا لحضرتك جدا بس سوال هل الخورزميات ده مهم في مجال الذكاء الاصطناعي بشكل عام
  15. في البداية يجب أن تعلم أن جانغو هو إطار عمل بايثون، لذلك: أوّل شيء هو القيام بتثبيت Python: توجه إلى موقع Python الرسمي، وقم بتحميل أحدث نسخة (حاليا هي نسخة 3.12.3). ملاحظة: عند قيامك بتثبيت Python لا تنسَ إضافته إلى Path Variables (فهذا مهم جداً ويحل الكثير من المشاكل) الآن سنقوم بتثبيت جانغو: وبالاطلاع على موقع Django الرسمي، نلاحظ أن طريقة تثبيته لا تختلف عن أية مكتبة أخرى: نكتب الأمر التالي و ننتظر حتى يتم التثبيت: الآن نحن جاهزون لإنشاء أول مشروع لنا في الجانغو: نفتح موجه الأوامر (CMD/Terminal) في المسار الذي نريد إنشاء المشروع به نقوم بإنشاء مشروع جديد باستخدام الأمر التالي: django-admin startproject my_django_project ثم ندخل إليه عن طريق: cd my_django_project يمكننا الآن أن نشغل المشروع عن طريق الأمر التالي: python manage.py runserver فيظهر لنا النتيجة التالية: ملاحظة أخيرة: ينصح عند عملك على مشاريع بإطار عمل جانغو، إنشاء بيئة عمل افتراضية (Virtual Environment) وذلك للاحتفاظ بإصدارات الحزم (packages) المثبتة لمشروعك ضمن المشروع نفسه وتجنب أية تضاربات ومشاكل، يمكنك الاستفادة من المقالات التالية: إعداد بيئة العمل للمشاريع مع بايثون - بواسطة دكتوري القدير Bassel Alkhatib ما فائدة تثبيت البيئة الإفتراضية virtual environment في البرمجة؟ - بواسطة يوسف شعبي إعداد بيئة تطوير تطبيقات جانغو Django - بواسطة Ola Abbas أرجو أن يساعدك ذلك وأتمنى لك التوفيق.
  16. لا أظن ذلك، فالتخصص أصبح مطلوبا بشكل كبير وهاته التخصصات لم يعد بالإمكان الإلمام بها مع بعضها بصورة كبيرة. ولذلك فإنك قد تجد بعض المناصب الوظيفية المفتوحة التي تتطلب واحدة فيهما على الأكثر، على أن الإلمام ببعض أساسيات الأمن السيبراني وممارسات الأمان عبر الويب والخوادم مطلوبة. ولكن هذا لا يمنع من التخصص في إحداهما والتركيز عليها بشكل أكبر. ولذلك فإن الشركات تعمد إلى توظيف متخصصين بدل شخص واحد يدرك المجالين بشكل عام أو إجمالي.
  17. الملف المرفق لا يعبر إلا عن كود بصفحة عرض معينة، ولا يمكن منها تنبؤ المشكلة بطبيعة الحال. ولكن لمثل هاته المشاكل الشائعة تأكدي مما يلي: من أن المنفذ المستخدم في ملف تكوين Laravel هو المنفذ الصحيح (DB_PORT) من أن بيانات قاعدة البيانات المستعملة صحيحة. (DB_USERNAME, DB_NAME, DB_PASSWORD) من أن خدمة MySQL لديك مشغلة بالفعل (يمكنك التأكد من ذلك من خلال xampp Panel) في حالة استمرار المشكلة، يرجى ارفاق صورة عن المشكلة أو نص رسالة الخطأ التي تظهر.
  18. وعليكم السلام، مشكلة الحقيبة (Knapsack Problem) دي واحدة من المشاكل اللي بتقابل الناس اللي بيشتغلوا في علوم الحاسب، وهي من نوع المشاكل اللي بتدور على أحسن طريقة لتحميل حاجات بأوزان وقيم مختلفة جوه حقيبة أو صندوق بسعة محدودة، علشان نحاول نزود القيمة الكلية بتاعت اللي جوا الحقيبة دي. الفكرة منها ممكن تتستخدم في حاجات كتير زي تحميل البضايع أو توزيع الموارد. الأنواع الرئيسية لمشكلة الحقيبة: 1. 0/1 Knapsack Problem: يا تاخد الحاجة كلها يا تسيبها خالص. 2. Fractional Knapsack Problem: تقدر تاخد جزء من الحاجة في الحقيبة. 3. Bounded Knapsack Problem: كل حاجة ليها عدد محدود تقدر تاخده. خوارزميات لحل مشكلة الحقيبة: 1. الخوارزمية الجشعة (Greedy Algorithm): - بتستخدم لمشكلة الحقيبة الجزئية. - الفكرة هي إنك تاخد الحاجات حسب نسبة القيمة للوزن، من الأعلى للأقل، وتحطها في الحقيبة لحد ما تمتلئ. - بتكون سريعة بس مش دايماً بتجيب الحل الأمثل للأنواع التانية من المشكلة. 2. البرمجة الديناميكية (Dynamic Programming): - دي الطريقة المعتادة لحل مشكلة الحقيبة 0/1. - بتقسم المشكلة لمشاكل أصغر وتحفظ النتايج بتاعتها علشان متتحسبش كتير. - بتديك حل دقيق بس ممكن تكون غالية من ناحية الذاكرة والوقت لو السعة كبيرة. 3. Branch and Bound: - بتستخدم لما تكون عايز حل دقيق لمشكلة الحقيبة 0/1. - بتستخدم تقنيات لتقليم الأشجار علشان تتجنب الحالات اللي مش هتجيب حل أحسن من الحل الأحسن المعروف. 4. Approximation Algorithms: - لما تكون محتاج حل سريع أكتر من إنك تحصل على الحل الأمثل. - بتوفر حلول قريبة من الحل الأمثل وغالبًا تكون كفاية لكتير من الاستخدامات العملية. يلا بينا نشوف مثال عملي على مشكلة الحقيبة باستخدام البرمجة الديناميكية لحل 0/1 Knapsack Problem. في المشكلة دي عندنا حاجات كل واحدة ليها وزن وقيمة، وعايزين نعرف إيه الحاجات اللي لازم نشيلها في الحقيبة علشان تكون الوزن تحت الحد والقيمة أعلى ما يمكن. المشكلة: - عندنا حقيبة سعتها 50 وحدة وزن. - عندنا أربع حاجات بالمواصفات دي: - حاجة 1: وزن = 10 وحدة، قيمة = 60 وحدة. - حاجة 2: وزن = 20 وحدة، قيمة = 100 وحدة. - حاجة 3: وزن = 30 وحدة، قيمة = 120 وحدة. - حاجة 4: وزن = 40 وحدة، قيمة = 240 وحدة. الحل بالبرمجة الديناميكية: هنستخدم جدول الصفوف بيمثل القيم والأعمدة بتمثل الأوزان من صفر لحد الحد الأقصى للحقيبة. الهدف إن كل خلية في الجدول تعكس القيمة القصوى اللي ممكن تتحقق بالوزن ده باستخدام الحاجات لحد الصف ده. هنبدأ نملأ الجدول ونحسب القيمة القصوى خطوة بخطوة: def knapsack(W, weights, values, n): # إنشاء جدول K K = [[0 for x in range(W + 1)] for x in range(n + 1)] # بناء الجدول K[][] for i in range(n + 1): for w in range(W + 1): if i == 0 or w == 0: K[i][w] = 0 elif weights[i-1] <= w: K[i][w] = max(values[i-1] + K[i-1][w-weights[i-1]], K[i-1][w]) else: K[i][w] = K[i-1][w] return K[n][W] # المعطيات values = [60, 100, 120, 240] # قائمة بالقيم weights = [10, 20, 30, 40] # قائمة بالأوزان W = 50 # الوزن الأقصى للحقيبة n = len(values) # عدد العناصر # دعوة الدالة result = knapsack(W, weights, values, n) print("القيمة القصوى التي يمكن الحصول عليها هي", result) في الكود ده: - knapsack دي الدالة اللي بتبني الجدول الديناميكي علشان نحسب القيمة القصوى. - الجدول K عبارة عن جدول ثنائي الأبعاد بيتم إنشاؤه بمقاس (n+1) x (W+1)، وهنا n هي عدد العناصر و W هو الوزن الأقصى. - في الحلقات، بنفحص كل وزن ممكن من 0 لغاية W لكل عنصر. إذا كان العنصر يقدر يتحمل بالوزن الحالي، هنشوف هل من المفيد إضافته ولا لأ، وده بنقرره بالمقارنة بين قيمة الخلية الحالية وقيمة الخلية اللي قبلها مضاف إليها قيمة العنصر. - في النهاية، K[n][W] هتحتوي على القيمة القصوى اللي يمكن تحقيقها بالوزن الأقصى W. النتيجة اللي هتطلع في الآخر هتقول لنا إيه أكبر قيمة ممكن نحققها من العناصر دي لما نملا الحقيبة بالوزن الأقصى المسموح بيه. ودي طريقة ممتازة تساعدنا نعرف نختار الأحسن ونستغل المساحة المتاحة بشكل كويس. يمكنك القراءه اكثر عن مسألة حقيبة الظهر المجزأة من هنا و عن مسألة حقيبة الظهر ‎0-1 من هنا
  19. مبدئيا، لا يوجد بديل مباشر ولكن يمكنك استخدام بعض الوسائل الأخرى لمقاربة نفس الفكرة. مثل استخدام مكتبة مثل readline التي تأتي مدمجة مع Node.js. بحيث أن هاته المكتبة تتيح لك قراءة إدخال المستخدم من سطر الأوامر. إليك مثالا: const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question('مرحبا، كيف الحال؟ ', (answer) => { console.log(`شكرا على إجابتك بـ: ${answer}`); rl.close(); });
  20. جرب استخدام بطاقة ائتمان أو ديبت من بنك آخر إذا كان ذلك ممكنًا، وتحقق من صحة تفاصيل البطاقة والتأكد من أنها تدعم الدفع عبر الإنترنت. أما إذا استمرت المشكلة، فالخطوة الصحيحة هي الاتصال بدعم العملاء لمزود الخدمة للحصول على المساعدة اللازمة. يمكنك الوصول إليها من هنا.
  21. ضف بعض التنسيقات الأخرى لطبقة overlay لكي يمكنها التموضع بصورة صحيحة. أعطها عرضا كاملا واجعلها تتموضع بشكل absolute داخل حاويتها: header .overlay { background-image: linear-gradient(top right, rgba(46,178,181,0.8), rgba(197,203,50, 0.8)); min-height: 100vh; min-width: 100vw; position: absolute; top: 0; right: 0; } طبعا لا تنسى اعطاء وضعية relative للحاوية المباشرة لها: header{ position: relative; }
  22. جرب التأكد من كل من التالي: من وجود ملف .htaccess في المسار الصحيح على السيرفر. من أن محرك إعادة التوجيه (RewriteEngine) مفعل. (RewriteEngine On) من أن الشروط (RewriteCond) تعمل بشكل صحيح للتحقق من عدم وجود الملف أو المجلد المطلوب. من أن القاعدة (RewriteRule) مكتوبة بشكل صحيح وتتوافق مع تنسيق الروابط الجديدة التي ترغب في تطبيقها. ان كان ذلك وما زال يتم عرض الخطأ، قد يكون هناك مشكلة في إعدادات الخادم أو تكوين Apache لديك. في هذه الحالة، يمكنك مراجعة سجلات الخطأ (error logs) للخادم للعثور على تفاصيل أكثر حول الخطأ ومساعدتك في تحديد السبب الفعلي للمشكلة.
  23. السلام عليكوم ورحمة الله و بركاته اخواني في الله احتاج للمساعدة في تحويل روابط المنتدى من php إلى html حيث اني استخدمت الكود في هذا الموضوع :: https://academy.hsoub.com/questions/27506-إعادة-كتابة-الروابط-في-ملف-htaccess/ وبعد التعديل بشكل صحيح السيرفر يعطي خطأ 404 وهذا الكود : <IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{QUERY_STRING} t=(.*) RewriteRule ^showthread.php$ /t-%1.html? [R=301,L] RewriteCond %{QUERY_STRING} u=(.*) RewriteRule ^member.php$ /u-%1.html? [R=301,L] ######################################################### RewriteRule ^t-([^?]*).html$ /showthread.php?t=$1 [QSA,L] RewriteRule ^u-([^?]*).html$ /member.php?u=$1 [QSA,L] </IfModule> و هذا الكود <IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{QUERY_STRING} t=(.*) RewriteRule ^showthread.php$ /t-%1.html? [R=301,L] RewriteCond %{QUERY_STRING} u=(.*) RewriteRule ^member.php$ /u-%1.html? [R=301,L] ############################################ RewriteRule ^t-([^?]*).html$ /showthread.php?t=$1 [QSA,L] RewriteRule ^u-([^?]*).html$ /member.php?u=$1 [QSA,L] </IfModule>
  24. وعليكم السلام أخي أحمد، 1. في البداية نقوم باستيراد المكاتب الضرورية للعمل: import tkinter as tk from tkinter import ttk import pandas as pd 2. سأقوم بتشكيل جدول DataFrame بشكل يشبه مثالك وأنت لك حرية التعديل: data = { 'رقم الطالب': [11101, 11102, 11103], 'الاسم': ['أشرف', 'علي', 'عزام'], 'العلامة': [65, 79, 62] } df = pd.DataFrame(data) ملاحظة: في حال أردت قراءته من ملف يدعى "students.csv": df = pd.read_csv('students.csv') 3.نقوم بإعداد واجهة Tkinter: root = tk.Tk() root.title("إضافة السنوات الدراسية") 4.نقوم بإعداد الـ Treeview بالأعمدة المطلوبة: columns = ('رقم الطالب', 'الاسم', 'العلامة', 'السنة الدراسية') tree = ttk.Treeview(root, columns=columns, show='headings') for col in columns: tree.heading(col, text=col) tree.column(col, width=100) 5.نقوم الآن بإضافة البيانات إلى Treeview: for index, row in df.iterrows(): tree.insert("", index, values=list(row)) 6.لتنظيم الكود، سأقوم بإنشاء وظيفة لإضافة السنة الدراسية لكل صف: def add_year(): selected_item = tree.selection()[0] year = year_entry.get() tree.set(selected_item, 'السنة الدراسية', year) 7. نقوم بإنشاء حقل لإضافة السنة لكل صف: year_label = tk.Label(root, text="أدخل السنة الدراسية:") year_label.pack(side=tk.LEFT) year_entry = tk.Entry(root) year_entry.pack(side=tk.LEFT) add_button = tk.Button(root, text="إضافة", command=add_year) add_button.pack(side=tk.LEFT) tree.pack(expand=True, fill='both') 8. وفي النهاية نقوم بتشغيل الواجهة التي قمنا بإنشائها السطر التالي: root.mainloop() وهذه هي النتيجة: بحيث تحدد كل سطر تريده وتقوم بإضافة السنة التي تريدها: وفي النهاية أتمنى أن تكون قد حلت مشكلتك، وأتمنى لك التوفيق.
  25. يشير مصطلح prototype إلى اﻵلية التي ترث فيها الكائنات ميزات من بعضها في جافا سكريبت، ويختلف عملها عن الوراثة في غيرها من اللغات كائنية التوجه، وهذا ما سنشرحه في هذا المقال. ننصحك قبل أن تبدأ العمل معنا في هذه السلسلة أن تطلع على: أساسيات HTML. أساسيات عمل CSS أساسيات جافا سكريبت أساسيات البرمجة كائنية التوجه في جافا سكربت كما شرحناه في مقال أساسيات العمل مع الكائنات في جافا سكريبت. سلسلة من اﻷنماط المجرّدة حاول أن تنشئ في طرفية جافا سكريبت في متصفحك الكائن التالي: const myObject = { city: "Madrid", greet() { console.log(`Greetings from ${this.city}`); }, }; myObject.greet(); // Greetings from Madrid يمتلك الكائن خاصية واحدة لتخزين البيانات هي city وتابعًا واحدًا هو ()greet. فإن كتبت اسم الكائن تليه نقطة في الطرفية مثل .myobject، ستعرض الطرفية قائمة بجميع الخاصيات التي يمتلكها العنصر. وسترى إضافة إلى الخاصية city والتابع ()greet، الكثير من الخاصيات اﻷخرى! __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__ __proto__ city constructor greet hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf جرّب الوصول إلى إحداها: myObject.toString(); // "[object Object]" لقد نجح اﻷمر (حتى لو لم يكن واضحًا لك بالضبط ما الذي يفعله التابع ()toString هنا). فما قصة هذه الخاصيات اﻹضافية، ومن أين أتت؟ في الواقع يملك كل كائن في جافا سكريبت خاصية مضمنة تُدعى prototype وهي بحد ذاتها كائن أيضًا ويضم بدوره خاصية أو كائن مجرّد إن صح التعبير، مما يوّلد ما يُدعى سلسلة prototype chain. تنتهي السلسلة عند الوصول إلى كائن قيمة الخاصية prototype له تساوي null. ملاحظة:لا تُدعى الخاصية التي تشير إلى prototype بالاسم prototype، إذ ليس لها اسم معياري لكنها تُكتب بالممارسة العملية بالشكل _proto_. وتُعد الطريقة المعيارية للوصول إلى الخاصية prototype هي استخدام التابع ()Object.getPrototypeOf. عندما تحاول الوصول إلى إحدى خاصيات كائن، ولم يُعثر على الخاصية في الكائن نفسه، يجري البحث عنها ضمن الكائن prototype، وإن لم يُعثر عليها يجري البحث مجددًا ضمن الكائن prototype للكائن prototype حتى نهاية السلسلة، فإن لم يجدها، سيُعيد القيمة undefined. فعندما تُنفّذ التعليمة ()myObject.toString: يبحث المتصفح عن التابع toString ضمن الكائن myObject. إن لم يجده، سيبحث عنه في الكائن prototype للكائن myObject. يجده هناك ويستدعيه. لكن ما هو prototype للكائن myObject؟ لمعرفة ذلك، يمكننا استخدام الأمر: Object.getPrototypeOf(myObject); // Object { } سنجد أن prototype هو كائن يُدعى Object.prototype، وهو أبسط الكائنات prototype، وتمتلكه جميع الكائنات افتراضيًا، والكائن prototype الخاص به هو null. لذا يقع هذا الكائن في نهاية سلسلة كائنات prototype. لكن لا يمثل Object.prototype دائمًا prototype لكل كائن، جرّب ما يلي لترى: const myDate = new Date(); let object = myDate; do { object = Object.getPrototypeOf(object); console.log(object); } while (object); // Date.prototype // Object { } // null تنشئ الشيفرة السابقة كائن من النوع Date، ثم تنتقل ضمن سلسلة كائنات prototype الخاصة به وتسجل أسماء هذه الكائنات. وتظهر أن النوع المجرد للكائن myDate هو Date.prototype وprototype الخاص بهذا اﻷخير هو Object.prototype. وعندما تستدعي توابع مثل ()mydate2.getMonth، فأنت تستدعي في واقع اﻷمر توابع معرّفة ضمن النوع Date.prototype. إخفاء الخاصيات ما الذي يحدث إن عرّفت خاصية في كائن وكانت هناك خاصية معرّفة بنفس الاسم ضمن الكائن prototype له؟ ألق نظرة على الشيفرة التالية: const myDate = new Date(1995, 11, 17); console.log(myDate.getYear()); // 95 myDate.getYear = function () { console.log("something else!"); }; myDate.getYear(); // 'something else!' لا بد أن تكون النتيجة التي حصلت عليها متوقعة. ووفقًا لوصف سلسلة الكائنات المجردة، سيبحث المتصفح عن الخاصية ()getYear ضمن خاصيات myDate التي تحمل هذا الاسم، ولا يتحقق من خاصيات الكائن المجرد إلا في الحالة التي لم نعرّف فيها هذه الخاصية. لهذا عندما أضفنا التابع ()getYear حرفيًا إلى الكائن myDate تُستدعى هذه النسخة مباشرة ويُعرف هذا اﻷمر بإخفاء الخاصية shadowing. إعداد كائنات prototype هناك طرق مختلفة ﻹعداد وضبط هذه الكائنات في جافا سكريبت، و سنناقش هنا طريقتان: الأولى باستخدام ()Object.create والثانية استخدام الدوال البانية constructors. استخدام التابع ()Object.create يُنشئ التابع ()Object.create كائنًا جديدًا ويسمح لك بتخصيص كائن ليصبح prototype الجديد الخاص به، إليك مثالًا: const personPrototype = { greet() { console.log("hello!"); }, }; const carl = Object.create(personPrototype); carl.greet(); // hello! أنشأنا في الشيفرة السابقة كائنًا باسم personPrototype، يمتلك التابع ()greet، ثم أنشأنا كائنًا جديدًا باستخدام التابع ()Object.create وجعلنا personPrototype كائن prototype له. وبالتالي نستطيع اﻵن استدعاء التابع ()greet من خلال الكائن الجديد، لأن كائن prototype قد زوّده به. استخدام الدالة البانية تمتلك جميع الدوال في جافا سكريبت خاصية تًدعى prototype. وعندما تستدعي الدالة على شكل دالة بانية، تُضبط تلك الخاصية لتكون prototype للكائن المبني حديثًا (داخل الخاصية التي تُدعى _proto_ تقليديًا). لهذا، وعندما نضبط القيمة prototype للدالة البانية، نضمن أن الكائنات التي تُنشئها هذه الدالة تمتلك كائن prototype: const personPrototype = { greet() { console.log(`hello, my name is ${this.name}!`); }, }; function Person(name) { this.name = name; } Object.assign(Person.prototype, personPrototype); // or // Person.prototype.greet = personPrototype.greet; لقد أنشأنا هنا: كائنًا بالاسم personPrototype يمتلك التابع ()greet. دالة بانية ()Person تهيئ اسم الشخص الذي نحييه. وضعنا بعد ذلك التوابع المعرّفة ضمن الكائن personPrototype ضمن الكائن prototype للدالة البانية باستخدام التابع Object.assign. وهكذا ستمتلك الكائنات المبنية باستخدام الدالة ()Person prototype Person.prototype الذي يضم تلقائيًا التابع greet. const reuben = new Person("Reuben"); reuben.greet(); // hello, my name is Reuben! يشرح هذا أيضًا ما قلناه سابقًا بأن الكائن prototype للكائن myDate هو Date.prototype، إذ يمثّل الخاصية للبانية Date. الخاصيات المملوكة Own properties يمتلك الكائن الذي أنشأناه باستخدام البانية ()Person خاصيتين: الخاصية name التي ضبطنا قيمتها باستخدام الدالة البانية، لهذا تظهر مباشرة ضم الكائن Person. التابع ()greetالذي ضبُط من خلال الكائن prototype. من الشائع أن تشاهد هذا الأسلوب الذي تُعرّف فيه التوابع ضمن كائنات prototype، وتُعرّف فيه خاصيات البيانات ضمن الدوال البانية. ذلك أن التوابع تبقى نفسها عادة لجميع الكائنات التي ننشئها، لكننا غالبا ما نريد أن يأخذ كل كائن قيم مخصصة لخاصيات البيانات (كأن يكون لكل شخص اسم خاص). تُدعى الخاصيات التي تُعرّف مباشرة ضمن الكائن مثل الخاصية name بالخاصيات المملوكة Own Property، وبإمكانك التحقق من كون الخاصية مملوكة باستخدام التابع الساكن ()Object.hasOwn: const irma = new Person("Irma"); console.log(Object.hasOwn(irma, "name")); // true console.log(Object.hasOwn(irma, "greet")); // false ملاحظة: كما تستطيع استخدام التابع غير الساكن ()Object.hasOwnProperty في هذه الحالة لكننا ننصح باستخدام التابع الساكن ما أمكن. الكائنات prototype والوراثة تُعد كائنات prototype ميزة قوية ومرنة في جافا سكريبت، تسمح لك بإعادة استخدام الشيفرة ودمج الكائنات. وهي بالتحديد تدعم نوعًا من الوراثة inheritance، والتي هي ميزة من ميزات البرمجة كائنية التوجه OOP. إذ تسمح الوراثة للمبرمج التعبير عن فكرة مفادها أن بعض الكائنات هي نسخ أكثر تخصيصًا من كائنات أخرى. فلو كنا نبني نموذجًا عن مدرسة، فقد ننشئ كائنات مثل مدرّس أو طالب وكلاهما أشخاص ويمتلكان بعض الميزات المتشابهة كاﻷسماء مثلًا، لكن قد يكون لكل منهما ميزات إضافية تميّزه عن اﻵخر (كأن يكون للمدرس موّاد يدرّسها)، وقد تنجز نفس الميزات بطريقة مختلفة لكل منهما. لهذا نقول في البرمجة كائنية التوجه OOP بأن الطالب والمدرس كائنان يرثان من كائن آخر يُدعى شخص. أما في جافا سكريبت فيمكن للكائنين Professor و Student أن يمتلكا نفس الكائن المجرد Person، ويرثا الخاصيات التي يمتلكها كائن prototype كما يمكن أن نعرّف خاصيات وتوابع جديدة تناسب كل منهما. سنناقش في مقالات لاحقة مفهوم الوراثة إضافة إلى الميزات الأخرى للبرمجة كائنية التوجه وطريقة دعم جافا سكريبت لها. الخلاصة غطينا في مقالنا كائنات prototype في جافا سكريبت، وآلية تكوين سلاسل كائنات prototype التي تسمح للكائنات أن ترث ميزات من بعضها، كما ناقشنا الخاصية prototype وكيفية استخدامها في إضافة توابع إلى الدوال البانية وغيرها من النقاط التي تتعلق بكائنات prototype. ترجمة -وبتصرف- للمقال Object prototpes اقرأ أيضًا المقال السابق: أساسيات العمل مع الكائنات في جافا سكريبت وراثة الأصناف (Class inheritance) في جافاسكربت كيف أتعلم لغة جافا سكريبت من الصفر حتى الاحتراف لغة البرمجة بالكائنات Object-Oriented Programming
  1. عرض المزيد
×
×
  • أضف...