لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 07/14/24 في كل الموقع
-
انا كانت عاوز كتبها من الصفر اعشان افهمها بشكل افضل الان انا حاليا بدرس الشبكات العصبيه تمام الف شكراا لحضرتك بس هو اي ال exp ده الموجود في باثيون اه الexp ده داله موجود في مكتبه الmath شكراا لحضرتك جدا2 نقاط
-
1 نقطة
-
السلام عليكم لقد قمت بشراء دورة تطوير واجهات المستخدم عبر كارت الفيزا وتم سحب ضعف ثمن الدورة من الفيزا فكنت اريد ان تعيدو لي المال1 نقطة
-
لقد قمت بالتواصل مع مركز المساعده ولكن لم يتم الرد علي وارسلت ايميل ايضا لم يتم الرد عليه1 نقطة
-
ايه المفروض اعمله لو انا مش طالب فى حاسبات ومعلومات وعايز اتساوى بيه وانافسه فى سوق العمل هل المفروض ادرس المواد بتاعته مع التخصص بتاعى ولا اخد الاساسيات واتخصص على طول1 نقطة
-
كيفكم يا أصدقاء... كيف نقدر نعمل شرط على حقول فورم.... مثال... الحقل الخاصة ب عامود info اذا كان يساوي 780 يتم ارسال الفورم واذا لا اظهر لنا خطأ يرجى ملئ الحقل بالرقم الصحيح... السؤال الثاني.... كيف يمكننا جعل انبوت الصور يستقبل فقط الصور ولايستقبل ملفات غير الصور ويرفض ملفات excel bdf.... عنده الإرسال1 نقطة
-
هل نستطيع رفع backend مع قواعدالبيانات على vercel حيث ان backend مبنيه ب laravel1 نقطة
-
طيب كده طالب حاسبات مش هيبقى افضل منى علشان درس مواد انا معرفهاش؟ اصل انا سمعت بودكاست قبل كده لشخص جامد فى المجال قال اللى بيفرق بس انى دارس منهج حاسبات ومعلومات ولا لا هنا بقى كان قصده ايه علشان مش فاهم وايه هى المواد اللى يقصدها1 نقطة
-
1 نقطة
-
هناك خطأ في المقارنة التي تستخدمها للتحقق من حجم الملف، يجب أن تستخدم مقارنة أكبر أو تساوي بدلا من = لضمان أن الملف لا يتجاوز الحجم المحدد.1 نقطة
-
يمكنك إستخدام الكود التالي: <!DOCTYPE html> <html lang="ar"> <head> <meta charset="UTF-8"> <title>نموذج مع خيارات مرتبطة</title> </head> <body> <?php $infoError = $selectError = ""; $info = $select1 = $select2 = $select3 = $select4 = ""; if ($_SERVER["REQUEST_METHOD"] == "POST") { $info = $_POST['info']; $select1 = $_POST['select1']; $select2 = $_POST['select2']; $select3 = $_POST['select3']; $select4 = $_POST['select4']; if ($info != 780) { $infoError = "يرجى ملء الحقل بالرقم الصحيح."; } if (empty($select1) || empty($select2) || empty($select3) || empty($select4)) { $selectError = "يرجى اختيار قيمة لكل قائمة منسدلة."; } if (empty($infoError) && empty($selectError)) { echo "تم إرسال النموذج بنجاح!"; // يمكنك إضافة الكود لمعالجة النموذج هنا } } ?> <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> <label for="info">Info:</label> <input type="text" id="info" name="info" value="<?php echo htmlspecialchars($info);?>"> <span style="color:red;"><?php echo $infoError;?></span><br><br> <label for="select1">اختر الخيار الأول:</label> <select id="select1" name="select1"> <option value="" <?php if ($select1 == "") echo "selected";?>>اختر...</option> <option value="option1" <?php if ($select1 == "option1") echo "selected";?>>خيار 1</option> <option value="option2" <?php if ($select1 == "option2") echo "selected";?>>خيار 2</option> </select><br><br> <label for="select2">اختر الخيار الثاني:</label> <select id="select2" name="select2"> <option value="" <?php if ($select2 == "") echo "selected";?>>اختر...</option> <option value="option1" <?php if ($select2 == "option1") echo "selected";?>>خيار 1</option> <option value="option2" <?php if ($select2 == "option2") echo "selected";?>>خيار 2</option> </select><br><br> <label for="select3">اختر الخيار الثالث:</label> <select id="select3" name="select3"> <option value="" <?php if ($select3 == "") echo "selected";?>>اختر...</option> <option value="option1" <?php if ($select3 == "option1") echo "selected";?>>خيار 1</option> <option value="option2" <?php if ($select3 == "option2") echo "selected";?>>خيار 2</option> </select><br><br> <label for="select4">اختر الخيار الرابع:</label> <select id="select4" name="select4"> <option value="" <?php if ($select4 == "") echo "selected";?>>اختر...</option> <option value="option1" <?php if ($select4 == "option1") echo "selected";?>>خيار 1</option> <option value="option2" <?php if ($select4 == "option2") echo "selected";?>>خيار 2</option> </select> <span style="color:red;"><?php echo $selectError;?></span><br><br> <input type="submit" value="إرسال"> </form> </body> </html> حيث نستخدم كود PHP للتحقق من القيم عند إرسال النموذج، و نتحقق من أن كل قائمة منسدلة تحتوي على قيمة غير فارغة، إذا كانت هناك أخطاء، نعرض رسائل خطأ بجانب الحقول المعنية، أما إذا لم تكن هناك أخطاء، نظهر رسالة نجاح.1 نقطة
-
عندى 18 سنه ومتعلم الاساسيات وعندى معرفه عن كل مجال بس لسه محددتش هتخصص ايه الوقت المتاح كل يوم1 نقطة
-
للتحقق من قيمة الحقل info يمكنك إستخدام جافاسكريبت مع php حيث نفرض أنه يوجد لدينا نموذج HTML بالشكل التالي: <!DOCTYPE html> <html lang="ar"> <head> <meta charset="UTF-8"> <title>نموذج مع تحقق</title> </head> <body> <form name="myForm" action="submit.php" onsubmit="return validateForm()" method="post"> <label for="info">Info:</label> <input type="text" id="info" name="info"> <input type="submit" value="إرسال"> </form> </body> </html> بعدها نستخدم كود php لمراقبة الطلب و التأكد من القيمة: <?php if ($_SERVER["REQUEST_METHOD"] == "POST") { $info = $_POST['info']; if ($info != 780) { echo "يرجى ملء الحقل بالرقم الصحيح."; } else { echo "تم إرسال النموذج بنجاح!"; // يمكنك إضافة الكود لمعالجة النموذج هنا } } ?> نقوم بإنشاء ملف PHP باسم submit.php يتحقق الكود من طريقة الطلب للتأكد من أن النموذج تم إرساله باستخدام طريقة POST، ثم نحصل على قيمة الحقل "info" من بيانات النموذج، إذا كانت القيمة ليست 780، نظهر رسالة خطأ. إذا كانت القيمة صحيحة، نظهر رسالة نجاح. أما للتحقق من نوع الملف المقبول على أنه صورة في نموذج HTML باستخدام PHP نقوم بإنشاء ملف PHP باسم upload.php، بعدها نحصل على معلومات الملف المرفوع من الحقل "image"، و نستخدم دالة explode لفصل اسم الملف للحصول على الامتداد، ثم نحوله إلى حروف صغيرة باستخدام strtolower، ثم نتحقق من أن الامتداد ضمن الامتدادات المسموح بها (JPG, JPEG, PNG, GIF)، إذا كان الامتداد صحيحا، نتحقق من عدم وجود أخطاء أثناء رفع الملف (fileError === 0)، ثم نظهر رسالة نجاح إذا تم رفع الملف بنجاح، أو رسالة خطأ مناسبة إذا كانت هناك مشكلة: <?php if ($_SERVER["REQUEST_METHOD"] == "POST") { $file = $_FILES['image']; $fileName = $file['name']; $fileTmpName = $file['tmp_name']; $fileSize = $file['size']; $fileError = $file['error']; $fileType = $file['type']; $fileExt = explode('.', $fileName); $fileActualExt = strtolower(end($fileExt)); $allowed = array('jpg', 'jpeg', 'png', 'gif'); if (in_array($fileActualExt, $allowed)) { if ($fileError === 0) { if ($fileSize < 5000000) { // الحد الأقصى لحجم الملف 5MB $fileNameNew = uniqid('', true).".".$fileActualExt; $fileDestination = 'uploads/'.$fileNameNew; move_uploaded_file($fileTmpName, $fileDestination); echo "تم تحميل الملف بنجاح!"; } else { echo "حجم الملف كبير جدًا!"; } } else { echo "حدث خطأ أثناء تحميل الملف!"; } } else { echo "يرجى تحميل ملفات الصور فقط (JPG, JPEG, PNG, GIF)."; } } ?>1 نقطة
-
حسنا كيف لي بأن اضبط تصرفاتي أو لأكون اوضح ما تصرفات التي يجب تعامل بها مع زبون لإقناعه وعدم اغضابه أو ازعاجه أو إحراجه واعطاءه تقييم مناسب لنا1 نقطة
-
نأسف لذلك بشدة بشأن هذا الخطأ هذا مزعج لك طبعا. بخصوص هذا الأمر حول الأمور المالية يمكنك التواصل مع مركز المساعدة وتوضيح الأمر لهم وسيتم رد المبلغ بالتأكيد في أسرع وقت. شكرا لتفهمك..1 نقطة
-
1 نقطة
-
و عليكم السلام علي، في حال كنت تريد فقط استعمالها، فكافة المكتبات المتعلقة بالذكاء الاصطناعي توفر هذا التابع، مثل PyTorch و Tensorflow. و يمكنك استعمال numpy أيضًا للقيام بذلك. أما في حال كنت تريد كتابته من الصفر (و هذا أمر لا أنصح به إلا في حال كنت تريد التجربة) فكل ما ستحتاجه هو تابع exp في بايثون، فقط ابحث عن هذا التابع و عن معادلة ال tanh و ما تبقى سيكون عمليات طرح و تقسيم لا أكثر. حاول القيام بذلك فهذا يساعدك أكثر من إعطاءك الحل مباشرة، و لكن كما أخبرتك يفضل استعمال التوابع الجاهزة فهي تقوم ببعض عمليات التحسين الرياضي. تحياتي.1 نقطة
-
السلام عليكم اي هي المبياد الرياضيات في مجال الذكاء الاصطناعي ؟1 نقطة
-
مرحبًا علي، ليس واضح ما هو المقصود من سؤال، أي رأيت أنه يوجد أولمبياد رياضيات للذكاء الصنعي؟ في حال كان قصدك عما هو موجود على kaggle فهذا ليس عبارة عن أولمبياد و إنما مسابقة لبناء نموذج قادر على حل مسائل أولمبياد الرياضيات. تحياتي.1 نقطة
-
تقصد بعد زيادة المساحة؟ ربما هناك مساحة لم تقوم بإضافتها، وستجدها unlocated أي غير مخصص. لكن من الصورة ما أراه هو أنّ مساحة قرص الـ C هي 117.59 ولو أضفنا إليها المساحة الأخرى وهي 120.12 تصبح المساحة 237.71 أي 238 كما أشرت. أظن ما تقصده هو أنّ الهارديسك لديه مساحته هي 256 ككل، وذلك طبيعي فلن تحصل على المساحة المكتوبة على وحدة التخزين، بل مساحة أقل كما هو الحال في جميع وحدات التخزين. بسبب أنّ أنظمة التشغيل تقوم بحساب السعة التخزينية باستخدام النظام العشري (الأساس 10)، حيث يمثل 1 جيجابايت 1,000,000,000 بايت. بينما تستخدم الشركات المصنعة للنظام الثنائي (الأساس 2)، حيث يمثل 1 جيجابايت 1,073,741,824 بايت، وذلك الاختلاف في الحساب يؤدي إلى فرق في السعة المعروضة. أيضًأ عند تهيئة وحدة التخزين، يتم استخدام جزء من المساحة لإنشاء نظام الملفات (مثل NTFS أو FAT32) وجدول تخصيص الملفات، وتلك العملية تستهلك جزءًا من المساحة الإجمالية.1 نقطة
-
من خلال جافاسكريبت، أولاً إنشاء حقول Select مع IDs مختلفة و display: none لإخفائها في البداية، وإنشاء حقل input من نوع file لرفع الصور. نستخدم addEventListener لالتقاط event التغيير change التغيير في Select الأول، وعند تغيير Select الأول، يتم إظهار Select الثاني و إخفاء الباقي، وهكذا عند تغيير Select الثاني، يتم إظهار Select الثالث بناءً على اختيار Select الأول و الثاني. وإظهار حقل رفع الصور فقط عند اختيار "Bachelors" في Select الثالث. <!DOCTYPE html> <html> <head> <title>Dependent Select Fields</title> </head> <body> <label for="area">Area name:</label><br> <select id="area" name="H1"> <option value="">Select an area</option> <option value="region1">The first region</option> <option value="region2">The second area</option> <option value="region3">The third region</option> </select> <div id="side-container" style="display:none;"> <label for="side">Side:</label><br> <select id="side" name="H2"> <option value="">Select a side</option> <option value="side1">The first side</option> <option value="side2">The second side</option> <option value="side3">The third side</option> </select> </div> <div id="academic-container" style="display:none;"> <label for="academic">Academic:</label><br> <select id="academic" name="H3"> <option value="">Select academic level</option> <option value="bachelors">Bachelors</option> <option value="preparatory">Preparatory school</option> <option value="medium">Medium</option> </select> </div> <div id="jurion-container" style="display:none;"> <label for="jurion">Jurion:</label><br> <select id="jurion" name="H4"> <option value="">Select a jurion</option> <option value="engineer">Engineer</option> <option value="doctor">Doctor</option> </select> </div> <div id="tion-container" style="display:none;"> <label for="tion">Tion:</label><br> <select id="tion" name="H4"> <option value="">Select a tion</option> <option value="neer">Neer</option> <option value="tor">Tor</option> </select> </div> <div id="image-container" style="display:none;"> <label for="image">Image:</label><br> <input type="file" id="image" name="H5"> </div> <script> const areaSelect = document.getElementById('area'); const sideContainer = document.getElementById('side-container'); const academicContainer = document.getElementById('academic-container'); const jurionContainer = document.getElementById('jurion-container'); const tionContainer = document.getElementById('tion-container'); const imageContainer = document.getElementById('image-container'); areaSelect.addEventListener('change', () => { sideContainer.style.display = 'block'; academicContainer.style.display = 'none'; jurionContainer.style.display = 'none'; tionContainer.style.display = 'none'; imageContainer.style.display = 'none'; }); sideContainer.querySelector('select').addEventListener('change', () => { academicContainer.style.display = 'block'; }); academicContainer.querySelector('select').addEventListener('change', (event) => { const selectedValue = event.target.value; if (areaSelect.value === 'region1' && selectedValue === 'bachelors') { jurionContainer.style.display = 'block'; tionContainer.style.display = 'none'; } else if (areaSelect.value === 'region2' && selectedValue === 'bachelors') { jurionContainer.style.display = 'none'; tionContainer.style.display = 'block'; } else { jurionContainer.style.display = 'none'; tionContainer.style.display = 'none'; } if (selectedValue === 'bachelors') { imageContainer.style.display = 'block'; } else { imageContainer.style.display = 'none'; } }); </script> </body> </html>1 نقطة
-
قد تبدو لغة جافا سكريبت JavaScript للوهلة الأولى سهلةً للغاية، إلا أن اللغة أكثر دقة وقوة وتعقيدًا مما قد تعتقده، إذ تؤدي العديد من التفاصيل الدقيقة في جافا سكريبت إلى عدد من المشكلات الشائعة - نناقش 10 منها في هذا المقال- حيث نركز على المشكلات التي تمنع التعليمات البرمجية من العمل على النحو المطلوب لتكون على دراية بهذه المخاطر وتتجنبها في سعيك لأن تصبح مطور جافا سكريبت محترفًا. تعد جافا سكريبت في يومنا الحاليّ جوهرًا لمعظم تطبيقات الويب الحديثة تقريبًا. ولهذا السبب تقع مهمة اكتشاف مشاكل جافا سكريبت، والأخطاء التي تسببها في مقدمة اهتمامات مطوري الويب، كما أن اعتماد المكتبات والأطر القوية على جافا سكريبت لتطوير تطبيقات الصفحة الواحدة Single Page Applications أو اختصارًا SPA والرسومات والرسوم المتحركة ومنصات جافا سكريبت الموجودة من طرف الخادم ليس بالأمر الجديد، إذ أصبحت جافا سكريبت منتشرة في كل مكان في عالم تطوير تطبيقات الويب، وأصبح من المهمّ تعلّم لغة جافا سكريبت وإتقانها. قد تبدو جافا سكريبت للوهلة الأولى بسيطة جدًا، وفي الواقع تعدّ عملية إنشاء وظائف جافا سكريبت الأساسية في صفحة ويب مهمة بسيطةً إلى حدّ ما لأي مطور برمجيات ذي خبرة، حتى لو كان جديدًا إلى جافا سكريبت، ومع ذلك فإن اللغة أكثر دقة وقوة وتعقيدًا مما قد يعتقده المرء في البداية؛ في الواقع، يمكن أن تؤدي العديد من التفاصيل الدقيقة لجافا سكريبت إلى عدد من المشكلات الشائعة التي تمنعها من العمل، وسنناقش 10 منها هنا. من المهم أن تكون على دراية بهذه المشكلات وتتجنبها أثناء رحلتك لتصبح مطور جافا سكريبت محترفًا. مشكلة جافا سكريبت الأولى: المراجع المغلوطة لـ this ستجد دومًا ارتباكًا بين مطوري جافا سكريبت فيما يتعلق بـكلمة جافا سكريبت المفتاحية this مع تطوّر وزيادة تعقيد تقنيات برمجة جافاسكريبت وأنماط التصميم Design Patterns، بات هناك زيادة مقابلة في انتشار نطاقات المرجعية الذاتية self-referencing scopes ضمن دوال رد النداء callbacks والمنغلقات closures، التي تعد المصدر الأساسي إلى حد ما للارتباك مع this الذي يسبب مشاكل جافا سكريبت. انظر إلى المثال التالي: const Game = function() { this.clearLocalStorage = function() { console.log("Clearing local storage..."); }; this.clearBoard = function() { console.log("Clearing board..."); }; }; Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(function() { this.clearBoard(); // What is "this"? }, 0); }; const myGame = new Game(); myGame.restart(); تظهر نتائج تنفيذ الشيفرة البرمجية أعلاه الخطأ التالي: Uncaught TypeError: this.clearBoard is not a function لماذا؟ الأمر كله يتعلق بالسياق فسبب حدوث هذا الخطأ هو أنه عند استدعاء الدالة setTimeout()، فإنك في الواقع تستدعي window.setTimeout(). ونتيجة لذلك، تُعرَّف الدالة المجهولة anonymous function التي تُمرَّر إلى setTimeout() في سياق كائن window الذي لا يحتوي على تابع بالاسم ClearBoard(). الحل التقليدي لهذه المشكلة والمتوافق مع المتصفحات القديمة هو حفظ المرجع إلى this في متغير يمكن بعد ذلك توريثه عبر دالة منغلقة closure function، على سبيل المثال: Game.prototype.restart = function () { this.clearLocalStorage(); const self = this; // Save reference to 'this', while it’s still this! this.timer = setTimeout(function(){ self.clearBoard(); // Oh, OK, I do know who 'self' is! }, 0); }; ويمكن أن نستخدم حلًا مختلفًا في المتصفحات الأحدث وذلك يتضمن استخدام التابع ()bind كما يلي: Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(this.reset.bind(this), 0); // Bind to 'this' }; Game.prototype.reset = function(){ this.clearBoard(); // OK, back in the context of the right 'this'! }; مشكلة جافا سكريبت الثانية: الاعتقاد بوجود نطاق على مستوى كتلة شيفرة أحد أسباب حدوث ارتباك شائع بين مطوري جافا سكريبت (وبالتالي مصدر شائع للأخطاء) هو افتراض أن جافا سكريبت تنشئ نطاقًا جديدًا لكل كتلة تعليمات برمجية. فبالرغم من أن هذا الأمر صحيح في العديد من اللغات الأخرى، إلا أنه ليس صحيحًا في لغة جافا سكريبت، خذ بعين الاعتبار الشيفرة البرمجية التالية: for (var i = 0; i < 10; i++) { /* ... */ } console.log(i); // What will this output? إن كنت تظن أن استدعاء console.log() سيعطي خرجاً undefined أو خطأً ما، فتخمينك خاطئ. صدق أو لا تصدق، سيكون الخرج هنا هو 10. لماذا؟ في معظم اللغات البرمجية الأخرى، ستتسبب الشيفرة البرمجية السابقة في حدوث خطأ برمجي لأنّ دورة حياة المتغير (أو نطاقه) مقيّدةٌ ضمن كتلة for. أما في لغة جافا سكريبت، فالمتغير i يبقى داخل النطاق بعد اكتمال حلقة for، محتفظاً بالقيمة الأخيرة بعد الخروج من الحلقة. (يُعرف هذا التصرف باسم رفع المتغيرات) إن دعم النطاقات على مستوى الكتل موجود في جافا سكريبت عبر كلمة let المفتاحية. وكلمة let كانت مدعومةً بشكلٍ كبير من قبل المتصفحات وبيئنات تشغيل جافا سكريبت مثل Node.js منذ سنوات. وإن كان هذا جديداً عليك، حان الوقت لتتعلم المزيد حول نطاق المتغيرات scopes وكائنات prototype في جافا سكريبت. مشكلة جافا سكريبت الثالثة: التسبب بتسريب الذاكرة يعد تسرب الذاكرة memory leak مشكلةً حتمية تقريبًا في جافا سكريبت إن لم تكن تبرمج بتركيز لتجنبها، وهناك طرق عديدة لحدوث ذلك، ولكننا سنسلط الضوء فقط على اثنتين من أكثر حالات حدوثها شيوعًا. تسريب الذاكرة - المثال1: المراجع المعلقة للكائنات المحذوفة لنضع بعين الاعتبار هذه الشيفرة البرمجية: var theThing = null; var replaceThing = function () { var priorThing = theThing; // Hold on to the prior thing var unused = function () { // 'unused' is the only place where 'priorThing' is referenced, // but 'unused' never gets invoked if (priorThing) { console.log("hi"); } }; theThing = { longStr: new Array(1000000).join('*'), // Create a 1MB object someMethod: function () { console.log(someMessage); } }; }; setInterval(replaceThing, 1000); // Invoke 'replaceThing' once every second إن نفّذت الشيفرة البرمجية السابقة وراقبت استخدام الذاكرة، ستجد أنّ لديك تسريباً كبيراً للذاكرة - حوالي ميغابايت في الثانية الواحدة! لدرجة أن كانسات القمامة لن تكون قادرة على المساعدة. ما يعني أنّه يتم تسريب longStr في كلّ مرةٍ نستدعي فيها replaceThing. ولكن لماذا؟ لنفحص الشيفرة بشكلٍ أدقّ: يتضمن كلّ كائن theThing على كائن longStr بحجم ميغابايت واحد. عندما نستدعي replaceThing في كلّ ثانية فإنّه يحتفظ بالمرجع الخاص بكائن theThing السّابق داخل priorThing، هل من الممكن أن تكون هذه هي المشكلة؟ ذلك من المستبعد، إذ يتم بشكل مسبق تحصيل dereference (أي عملية إلغاء المرجع) priorThing في كلّ مرةٍ (عندما نعدّل قيمة priorThing عبر السطر priorThing = theThing;). بالإضافة إلى أنه ذلك، فنحن نحصل على قيمة priorThing داخل الدالة replaceThing وفي تابع unused، ما يعني أنه لم يُستخدم. ما يعني أنّنا لم نجد الإجابة على سؤالنا حول تسريب الذاكرة هنا. نحتاج إلى فهمٍ أعمق لآلية عمل جافا سكريبت الداخلية لفهم ما يحدث. عادةً ما تُطبَّق الدوال المغلّفة عبر كلّ دالة ضمن كائن متصل بكائنٍ بنمط القاموس الذي يمثّل النطاق المعجميّ lexical scope. إن استخدمت كلٌّ من الدالتين اللتين تم تعريفهما داخل replaceThing تعليمة priorThing، سيكون من المهمّ أن تحصل كلاهما على الكائن نفسه، حتى لو تم تعيين priorThing مرارًا وتكرارًا بحيث تشترك كلتا الدالتين في البيئة المعجمية lexical environment (البيئة التي تحتوي على معلومات حول المتغيرات المحلية والعامة بالإضافة إلى الدوال المتاحة في نطاق البرنامج عند تعريف الدالة) ذاتها. ولكن ما إن تستخدم المتغيرات من قبل أيٍّ مغلّف، ستصل إلى البيئة المعجميّة المشتركة بين جميع المغلّفات في هذا النطاق. وهذا الفارق الدقيق هو ما يؤدي إلى تسريب الذاكرة هذا. تسريب الذاكرة - المثال 2: المراجع الذاتية لنرى هذا الجزء من الشيفرة البرمجيّة: function addClickHandler(element) { element.click = function onClick(e) { alert("Clicked the " + element.nodeName) } } لتعليمة onClick هنا مغلّفًا يحافظ على مرجعٍ إلى element (عبر element.nodeName). وبإسناد onClick إلى element.click يُنشأ المرجع الدوار أي يصبح لدينا: element →onClick → element → onClick → element… ومن المثير للاهتمام أنّه حتّى إن أزلنا element من DOM، فسيمنع المرجع الذاتي circular reference (الذي يشير لنفسه بشكل دوري) أعلاه من أن نحصل على قيمة element و onClick ما يؤدي إلى تسريب الذاكرة. تجنّب تسريب الذاكرة: الأساسيّات تعتمد إدارة ذاكرة جافا سكريبت (وبشكلٍ خاصّ كنس البيانات المهملة ) بشكلٍ كبير على الوصول إلى الكائن. من المفترض أن تكون الكائنات التالية قابلة للوصول كما تعرف باسم "الجذور roots": الكائنات المشار إليها من أي مكان في مكدس الاستدعاءات call stack الحالي (أي جميع المتغيرات والمعاملات المحلية في الدوال التي تُستدعى حاليًا، وجميع المتغيرات في نطاق المغلّف). كلّ المتغيرات العامة. يُحتفظ بالكائنات في الذاكرة طالما يمكن الوصول إليها من أي من الجذور من خلال مرجع أو سلسلة من المراجع. يوجد في المتصفح أداة كنس مهملات تنظف الذاكرة التي تشغلها الكائنات غير القابلة للوصول؛ بمعنى آخر، تُزال الكائنات من الذاكرة فقط إذا اعتقد كانس المهملات أنه لا يمكن الوصول إليها. لسوء الحظ، من السهل أن تخلص بوجود كائنات "زومبي" قديمة لم تعد قيد الاستخدام ولكن لا يزال كانس المهملات يعتقد أنه يمكن الوصول إليها. مشكلة جافا سكريبت الرابعة: عدم فهم المساواة إحدى وسائل جافا سكريبت المرنة هي أنها ستحوّل أي قيمة في سياق بولياني إلى قيمة بوليانية تلقائيًا، ولكن في بعض الحالات يسبب ذلك إرباكًا بدلًا من توفير مرونة في التعامل، ومن المعروف أن التعبيرات التالية مزعجة للعديد من مطوري جافا سكريبت، على سبيل المثال: // All of these evaluate to 'true'! console.log(false == '0'); console.log(null == undefined); console.log(" \t\r\n" == 0); console.log('' == 0); // And these do too! if ({}) // ... if ([]) // ... على الرغم من كون العنصرين الأخيرين فارغين (مما قد يقودك إلى الاعتقاد بأنهما سيُقيَّمان إلى false)، فإن كلاً من {} و [] هما في الواقع كائنان، وسيُحوَّل أي كائن قسريًا إلى قيمة بوليانيّة مساوية إلى true في جافا سكريبت بما يتوافق مع معايير ECMA-262. وكما توضح هذه الأمثلة، فإن قواعد تحويل النوع القسريّ يمكن أن يكون في بعض الأحيان صعب الفهم. وفقًا لذلك، ما لم تكن ترغب بذلك بشكل صريح، فمن الأفضل عادةً استخدام === و ==! (بدلاً من == و =!) لتجنب أي آثار جانبية غير مقصودة لتحويل النوع القسريّ. (== و =! ينفذان تحويل النوع تلقائيًا عند مقارنة شيئين، بينما === و ==! يقومان بنفس المقارنة بدون تحويل النوع). وبما أنّنا نتحدّث عن تحويل النوع القسري والمقارنة بين النوعين، من المهمّ ذكر أن مقارنة NaN مع أيّ شيء (حتّى NaN!) سيعيد دائمًا false، بالتالي لن تستطيع استخدام عوامل المساواة (==، ===، !=، !==) لتحديد إذا ما كانت القيمة NaN أم لا، وعليك أن تستخدم بدلاً من ذلك الدالة العامة المبنية مسبقًا ()isNaN: console.log(NaN == NaN); // False console.log(NaN === NaN); // False console.log(isNaN(NaN)); // True مشكلة جافا سكريبت الخامسة: التلاعب بنموذج تمثيل المستند DOM غير الفعّال تسهّل جافا سكريبت التعامل مع DOM بشكل نسبي (كإضافة العناصر وتعديلها وإزالتها)، ولكنها لا تفعل ذلك مع التشديد على القيام بذلك بكفاءة. ومن أكثر الأمثلة شيوعًا هو الشيفرة البرمجية التي تضيف سلسلة من عناصر DOM واحدًا تلو الآخر، إذ تعد إضافة عنصر DOM عملية مكلفة، والتعليمات البرمجية التي تضيف عناصر DOM متعددة على التوالي غير فعالة ومن المحتمل ألا تعمل بشكلٍ جيد. أحد البدائل الفعالة عند الحاجة إلى إضافة عناصر DOM متعددة هو استخدام أجزاء المستند فقط، ما يؤدّي إلى تحسين الكفاءة والأداء. كمثال: const div = document.getElementById("my_div"); const fragment = document.createDocumentFragment(); const elems = document.querySelectorAll('a'); for (let e = 0; e < elems.length; e++) { fragment.appendChild(elems[e]); } div.appendChild(fragment.cloneNode(true)); بالإضافة إلى تحسين الكفاءة لهذا النهج، فإن إنشاء عناصر DOM المرفقة أمر مكلف، في حين أن إنشائها وتعديلها أثناء فصلها ثم إرفاقها يؤدي إلى أداء أفضل بكثير. مشكلة جافا سكريبت السادسة: الاستخدام الخاطئ لتعريف الدوالّ داخل حلقات for لننظر إلى هذه الشيفرة البرمجيّة: var elements = document.getElementsByTagName('input'); var n = elements.length; // Assume we have 10 elements for this example for (var i = 0; i < n; i++) { elements[i].onclick = function() { console.log("This is element #" + i); }; } بناءً على الشيفرة البرمجيّة أعلاه، إن كان هناك 10 عناصر إدخال، فإن النقر على أيٍّ منها سيعرض "هذا هو العنصر #10"! لأنه عند استدعاء onclick لأي من العناصر، ستكون حلقة for المذكورة أعلاه قد اكتملت وستكون قيمة i تساوي 10 (لجميع العناصر). لنرى كيف يمكننا تصحيح مشكلة جافا سكريبت هذه لتحقيق السلوك المطلوب: var elements = document.getElementsByTagName('input'); var n = elements.length; // Assume we have 10 elements for this example var makeHandler = function(num) { // Outer function return function() { // Inner function console.log("This is element #" + num); }; }; for (var i = 0; i < n; i++) { elements[i].onclick = makeHandler(i+1); } في هذه النسخة المنقحة ننفّذ makeHandler على الفور في كل مرة نمر فيها خلال الحلقة، وفي كل مرة يتم تلقي القيمة الحالية لـ i+1 وربطها بمتغير num محدد النطاق تعيد الدالة الخارجية الدالة الداخلية (التي تستخدم أيضًا متغير num المحدد هذا) ويتم تعيين onclick الخاصة بالعنصر على تلك الدّالة الداخلية. وهذا يضمن أن كل نقرة تتلقى وتستخدم قيمة i المناسبة (عبر المتغير num المحدد). مشكلة جافا سكريبت السابعة: الفشل في الاستفادة بشكل صحيح من الوراثة النموذجية يفشل عددٌ كبيرٌ من مطوري جافا سكريبت في فهم ميزات الوراثة النموذجيّة بشكل كامل، وبالتالي الاستفادة منها بشكل كامل. إليك مثالًا بسيطًا: BaseObject = function(name) { if (typeof name !== "undefined") { this.name = name; } else { this.name = 'default' } }; يبدو ذلك واضحًا ومباشراً. إن أعطيت اسمًا، استخدمه، وإلّا فاضبط الاسم كـ "افتراضيّ default"، مثلاً: var firstObj = new BaseObject(); var secondObj = new BaseObject('unique'); console.log(firstObj.name); // -> Results in 'default' console.log(secondObj.name); // -> Results in 'unique' ولكن ماذا لو قمنا بهذا: delete secondObj.name; ثمّ سنحصل على: console.log(secondObj.name); // -> Results in 'undefined' ولكن أليس من الأفضل أن يعود هذا إلى "default"؟ يمكننا القيام بذلك بسهولة إذا عدلنا الشيفرة الأصلية للاستفادة من الوراثة النموذجية، على النحو التالي: BaseObject = function (name) { if(typeof name !== "undefined") { this.name = name; } }; BaseObject.prototype.name = 'default'; في هذه النسخة، ترث تعليمة BaseObject ملكيّة name من كائن prototype، الذي يوجد بشكلٍ افتراضيّ في تعليمة default، وبالتالي، إذا استدعي الباني بدون اسم، فسيعيّن الاسم افتراضيًا عبر default، وبالمثل إن أزيلت خاصية name من نسخة BaseObject، فستجرى عملية بحث في سلسلة النموذج الأولي واسترداد خاصية name من كائن prototype حيث تظل قيمته default. والآن نحصل على: var thirdObj = new BaseObject('unique'); console.log(thirdObj.name); // -> Results in 'unique' delete thirdObj.name; console.log(thirdObj.name); // -> Results in 'default' مشكلة جافا سكريبت الثامنة: إنشاء مراجع خاطئة لتوابع النُّسَخ Instance Methods لنعرّف كائنًا بسيطًا وننشئ نسخةً له كما يلي: var MyObjectFactory = function() {} MyObjectFactory.prototype.whoAmI = function() { console.log(this); }; var obj = new MyObjectFactory(); والآن لننشئ مرجعاً للتابع whoAmI لضمان سهولة العمل ولنتمكن من الوصول إليه فقط من خلال whoAmI() بدلاً من التابع ()obj.whoAmI الأطول: var whoAmI = obj.whoAmI; وللتأكّد؛ خزّنّا مرجعًا للدالة، لنطبع القيمة لمتغيّرنا الجديد whoAmI: console.log(whoAmI); الخرج: function () { console.log(this); } يبدو الأمر جيدًا حتّى الآن. ولكن لنرى الفرق عندما نستدعي ()obj.whoAmI بدلاً من مرجع السهولة الخاص بنا ()obj.whoAmI: obj.whoAmI(); // Outputs "MyObjectFactory {...}" (as expected) whoAmI(); // Outputs "window" (uh-oh!) ما الخطأ الذي حصل؟ استدعينا التابع ()obj.whoAmI في مساحة الاسم العامة، لذا فإن this تُضَمّ إلى window (أو في الوضع الدّقيق إلى undefined)، وليس إلى نسخة obj الخاصة بكائن MyObjectFactory! بمعنًى آخر، قيمة this تعتمد على سياق استدعائها. تقدم الدوالّ السهمية {} < = (params) بدلاً من {} (function (params this ثابتة وهذا ليس مبنيًّا على سياق الاستدعاء مثل this للدوالّ الطبيعية، مما يمنحنا الحلّ البديل: var MyFactoryWithStaticThis = function() { this.whoAmI = () => { // Note the arrow notation here console.log(this); }; } var objWithStaticThis = new MyFactoryWithStaticThis(); var whoAmIWithStaticThis = objWithStaticThis.whoAmI; objWithStaticThis.whoAmI(); // Outputs "MyFactoryWithStaticThis" (as usual) whoAmIWithStaticThis(); // Outputs "MyFactoryWithStaticThis" (arrow notation benefit) من الممكن أنّك لاحظت أنّه على الرغم من حصولنا على خرج مطابق إلا أن this هي مرجع لدالة المصنع factory التي تنشئ الكائن وليس مرجعًا إلى نسخة الكائن نفسها وبدلاً من محاولة إصلاح هذه المسألة، من المفيد التفكير في طرق التعامل مع جافا سكريبت التي لا تعتمد على this (أو حتى new) على الإطلاق. مشكلة جافا سكريبت التاسعة: استخدام سلسلة كوسيط أول لدالة setTimeout أو setInterval بدايةً؛ لنوضّح أمرًا ما: استخدام سلسلة كوسيط أول لدالة setTimeout أو setInterval ليس خطأً بحدّ ذاته. فهو شيفرةٌ برمجيّةٌ صحيحةٌ في جافا سكريبت، والمشكلة هنا تتعلق بالأداء والكفاءة. ما يتمّ التغاضي عنه غالبًا هو أنّه إن مررت سلسلة كوسيط أول إلى setTimeout أو setInterval، فإنها ستمرر إلى باني الدالة لتحوَّل إلى دالة جديدة، ويمكن أن تكون هذه العملية بطيئة وغير فعالة، ونادرًا ما تكون ضرورية. البديل لتمرير سلسلة كوسيط أول لهذه التوابع هو تمرير دالة بدلاً من ذلك. لنلقي نظرة على المثال التالي، هنا سنستخدم setInterval و setTimeout استخدامهما الاعتيادي، حيث نمرر سلسلة كمعامل أول: setInterval("logTime()", 1000); setTimeout("logMessage('" + msgValue + "')", 1000); ويكون الخيار الأفضل في هذه الحالة هو تمرير دالة كوسيط أولي مثل: setInterval(logTime, 1000); // Passing the logTime function to setInterval setTimeout(function() { // Passing an anonymous function to setTimeout logMessage(msgValue); // (msgValue is still accessible in this scope) }, 1000); مشكلة جافا سكريبت العاشرة: الفشل في استخدام الوضع الصارم الوضع الصارم strict mode (بما في ذلك استخدام ;'use strict' في بداية ملفات جافا سكريبت المصدرية) هو وسيلة لفرض تحليل أكثر دقّة ومعالجة الأخطاء في الشيفرة البرمجية الخاصة بك في وقت التنفيذ أيضًا. كوسيلة لجعلها أكثر أمانًا. ورغم أن الفشل في استخدام الوضع الصارم لا يشكل "خطأً" حقيقيًا، إلا أنّ استخدامه يتزايد بشكلٍ كبير ويتم تشجيعه بشكلٍ كبير، كما يعدّ تجاهله أمرًا سيّئًا. هذه بعض الميّزات للوضع الصارم: يجعل تصحيح الأخطاء أسهل. يؤدي وجود الأخطاء في الشيفرة البرمجية التي كان من الممكن تجاهلها أو التي كانت ستفشل بصمت إلى إنشاء أخطاء أو رمي استثناءات، ما ينبهك بشكلٍ مسبق إلى مشاكل جافا سكريبت في مشروعك البرمجي ويوجهك بشكل أسرع إلى مصدرها. يمنع المتغيّرات العامة العرضية. يؤدي تعيين قيمة لمتغير غير معلن عنه تلقائيًا دون الوضع الصارم إلى إنشاء متغير عام بهذا الاسم. وهذا هو أحد أكثر أخطاء جافا سكريبت شيوعًا. وعند تفعيل الوضع الصارم يؤدي ذلك إلى إظهار خطأ. يوقف تغيير النوع التلقائي لـ this. بدون الوضع الصارم، يفرض مرجع إلى قيمة this الخالية أو غير المحددة تلقائيًا إلى المتغير globalThis. يمكن أن يسبب هذا العديد من الأخطاء. بينما في الوضع الصارم، تؤدي الإشارة إلى هذه القيمة الخالية أو غير المحددة إلى ظهور خطأ. يمنع تكرار أسماء الخاصيات أو قيم المعاملات. يظهر الوضع الصارم خطأً عند تحديد اسمين مماثلين لخاصية كائنٍ واحد (مثال؛ var object = {foo: “bar”, foo: “baz”};) أو اسمًا مكرّرًا لدالّة (مثال؛ function foo(val1, val2, val1){})، وبالتالي يساعد باكتشاف ما يكاد أن يكون خطأً في شيفرتك الذي ربما تكون قد أهدرت وقتًا طويلاً في تعقبه. يجعل ()eval أكثر أمانًا. هناك بعض الاختلافات في الطريقة التي تتصرف بها الدالة ()eval بين الوضعين الصارم وغير الصارم . والأهم من ذلك، في الوضع الصارم، لا يتم تُنشئ المتغيرات والدوال المعرّفة داخل تعليمة ()eval في النطاق المحتوي. (بل تُنشأ في النطاق المحتوي في الوضع غير الصارم، الذي يمكن أن يكون أيضًا مصدرًا شائعًا لمشاكل جافا سكريبت). يعطي خطأً عند استخدامٍ خاطئٍ لـ delete. لا يمكن استخدام عامل delete (الذي يستخدم لإزالة الخواص من الكائنات) على خواص كائنات غير قابلة للضبط nonconfigurable properties. ستفشل التعليمات البرمجية غير الصارمة بصمت عند إجراء محاولة لحذف خاصيةٍ غير قابلة للضبط، في حين أن الوضع الصارم سيعطي رسالة خطأ في هذه الحالة. التخفيف من مشاكل جافا سكريبت باستخدام نهج أكثر ذكاءً كما هو الحال مع أي تقنية، كلما فهمت كيفية عمل جافا سكريبت بشكلٍ أفضل، كلما كانت التعليمات البرمجية الخاصة بك أكثر اعتمادية، وكلما تمكنت من تسخير قوة اللغة بشكل أكثر فعالية. بالمقابل، فإن الافتقار إلى الفهم الصحيح لنماذج ومفاهيم جافا سكريبت هو المكان الذي تكمن فيه العديد من مشاكلها، والتعرف جيدًا على الفروق الدقيقة في اللغة وخفاياها هو الاستراتيجية الأكثر فعالية لتحسين كفاءتك وزيادة إنتاجيتك. أسئلة شائعة لنختم مقالنا بجملة من الأسئلة الشائعة حول جافاسكريبت: ما هي الأخطاء الشائعة في جافا سكريبت؟ الأخطاء الشائعة التي يرتكبها المطورون خلال البرمجة باستخدام جافا سكريبت تتضمن الفهم الخاطئ لكيفية عمل كلمة this المفتاحية، والافتراض الخاطئ حول النطاق الكتلي والفشل في تفادي تسريبات الذاكرة. تسببت مسيرة تطوير جافا سكريبت عبر الزمن بالعديد من الأخطاء في حال الاعتماد على أنماط البرمجة القديمة. كيف يمكنني تطوير مهاراتي في جافا سكريبت؟ يمكنك تطوير مهاراتك في جافا سكريبت عن طريق الالتزام بالممارسات المثلى عند كتابة الشيفرة البرمجية، وقراءة التفاصيل الخفية في لغة البرمجة لتكون على علم بمزاياها المتقدمة وأوجه قصورها. لمَ أكتب شيفرة برمجية معرضة بالأخطاء؟ قد تبدو الشيفرة البرمجية المعرضة للأخطاء على ما يرام عند النظر إليها للوهلة الأولى، إلا أنه وبتعلمك لهذه المشاكل الشائعة في جافا سكريبت فستبدي فهمًا أكبر للأنماط البرمجية التي تتسبب بالمشاكل وتتعلم طرق تفاديها في شيفرتك البرمجية. هل جافا سكريبت كثيرة المشاكل؟ قد يزعم البعض أن لغة جافا سكريبت بنفسها مسببة للمشاكل، وعلى الرغم من أنها تشكو من بعض أوجه القصور إلا أنها شائعة ومنتشرة في كل مكان، لذا تعلّم كيفية اكتشاف أخطائها وتصحيحها أمر يستحق الجهد إذا كنت ستعمل معها (وهذا هو الحال مع معظم المطوّرين في يومنا الحالي). ترجمة -وبتصرف- لمقال The 10 Most Common JavaScript Issues Developers Face لكاتبه Ryan J. Peterson اقرأ أيضًا كيفية التعامل مع الأخطاء البرمجية الزلات البرمجية والأخطاء في جافاسكريبت المتغيرات والعوامل والأخطاء البرمجية في لغة جافا كيف تصبح مبرمجًا محترفًا1 نقطة