لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 10/16/21 في كل الموقع
-
لدي عدد من الجداول أحاول الربط بينهم عن طريق id وجلب قيمة عمود الاسم من كل منهم ولكنه يأخذ الكثير من الوقت، كيف أحل المشكلة2 نقاط
-
لدي جدول مفتاحه الأساسي مكون من اجتماع اثنين من الأعمدة col1 , col2 كيف أستطيع تحقيق الربط على هذا الأساس؟2 نقاط
-
لدي مشروع عبارة عن موقع الكتروني مبني بلغة python بايثون وإطار عمل دجانغو، أريد شرح خطوات رفعه على الاستضافة وتشغيله1 نقطة
-
Modernizr هي مكتبة JavaScript تقوم باكتشاف ميزات HTML5 وCSS3 التي يدعمها متصفح الزائر. قيامها بذلك بُتيح للمطور معرفة الخواص والتقنيات الجديدة المدعومة بشكل مُضمن في المتصفح والتي بإمكانه استخدامها بشكل مُباشر إضافة إلى تلك التي لا يدعمها، والتي يجب عليه أن يدعمها بطريقة تراجعية Fallback. يُطلق على هذه التقنية اسم اكتشاف الميزات (الخاصة) والتي تُعتبر تقنية أنجح بكثير من تقنية "التعرف على المتصفح" (browser sniffing). تُعتبر Modernizr في غاية الأهمية لدى استكشاف خواص CSS3 المدعومة على المتصفح، لكننا سنركز في هذا المقال على HTML5 فقط، رغم أن مبدأ عمل المكتبة هو نفسه مع كلي الأمرين. تجدر الإشارة إلى أن Modernizr لا تقوم بتعويض النقص الناتج عن عدم دعم المتصفح لبعض الخواص أو ما يُعرف بالـ Polyfills، كل ما تقوم بها المكتبة هو استكشاف إن كان المتصفح يدعم خاصية مُعينة من عدمه، لكنه يبقى بإمكانك استخدام Modernizr كجزء من آلية تعويض ذلك النقص. لا يدعم الإصدار الثامن من متصفح Internet Explorer والإصدارات التي تسبقه الخواص الجديدة للـ HTML5 بشكل قياسي، ولهذا إن احتجت دعم هذه المتصفحات فإنه يجب عليك تعويض هذا النقص ببعض الـ JavaScript. يُمكنك القيام بذلك باستخدام الشفرة التي سيلي استعراضها، كما يُمكنك القيام بذلك باستخدام HTML5 Shiv الخاصة بـ @rem والتي تشمل جميع الخواص الجديدة. يساعدك Modernizr في القيام بذلك، وبالتالي فإن المرور عبر تضمين الـ Shiv غير ضروري. البداية بداية سنحتاج إلى ملف HTML: <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello Modernizr</title> <script src="modernizr.js"></script> </head> <body> </body> </html> كما هو ظاهر في هذه الشفرة فإننا سنحتاج إلى ملف modernizr.js والذي يُمكنك بناء نسخة منه ومن ثم تحميله بناء على الخواص التي ترغب من التحقق من دعمها. يُمكنك القيام بذلك عبر اختيار Production (الصورة الأولى) ومن ثم اختيار تلك الخواص مثلما هو ظاهر في الصورة الثانية. هذا الأمر يسمح باستخدام ملف صغير الحجم لأننا لا نقوم بتضمين جميع الخواص التي يُمكن لـ Modernizr استكشافها. يُوفر الموقع نسخة تطوير خاصة بالمكتبة، لكنه قبل أن ترفع موقعك إلى خادمك الخاص فإنك ستحتاج إلى ملف Production الذي يستكشف الخواص التي تحتاج استكشافها فقط. خيارا تحميل Modernizr اختيار خواص ومن ثم بناء ملف Modernizr لاحظ أيضا في السطر الثاني في ملف HTML آنف الذكر وجود صنف no-js في وسم <html>. يقوم Modernizr باستبدال هذا الصنف بصنف js والذي يُمكن أن يكون له فائدة في ملف CSS الخاص بك. إلى جانب صنف js يُضيف Modernizr أصنافا لكل الخواص التي يدعمها المتصفح، وللخواص التي لا يدعمها يُضيف أصنافا تُسبق أسماؤها بـ no-. إليك مثالين عن الأصناف التي يُضيفها Modernizr على كل من متصفحي Chrome 16 و IE9: <html class="js flexbox canvas canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths"> <html class="js no-flexbox canvas canvastext no-webgl no-touch geolocation postmessage no-websqldatabase no-indexeddb hashchange no-history draganddrop no-websockets rgba hsla multiplebgs backgroundsize no-borderimage borderradius boxshadow no-textshadow opacity no-cssanimations no-csscolumns no-cssgradients no-cssreflections csstransforms no-csstransforms3d no-csstransitions fontface generatedcontent video audio localstorage sessionstorage no-webworkers no-applicationcache svg inlinesvg smil svgclippaths"> استكشاف العناصر يقوم Modernizr بإنشاء كائن جافاسكربت عام (Global Object) تحت اسم Modernizr مما يسمح لنا بالقيام باستعلامات حول مختلف خواص properties المتعلقة به وذلك عبر مناداة Modernizr.featurename (أين featurename هي اسم الخاصية المراد التأكد من دعمها على المتصفح). وبالتالي إن أردنا مثلا التأكد إن كان المتصفح يدعم canvas فإننا نكتب التالي: <script> if (Modernizr.canvas) { alert("This browser supports HTML5 canvas!"); } </script> جرب هذه الشيفرة على متصفح حديث وستظهر لك رسالة تُخبرك بأنه يدعم Canvas. بطبيعة الحال يُمكن أيضا التحقق ما إذا كان المتصفح لا يدعم خاصية مُعينة على النحو التالي: <script> if (Modernizr.canvas) { alert("This browser supports HTML5 canvas!"); } else { alert("no canvas :("); } </script> أو اختصار الأمر على النحو التالي: <script> if (!Modernizr.canvas) { alert("No canvas here"); } </script> استكشاف الخواص وتعويض النقائص باستخدام YepNope استعرضنا في المثال السابق أبسط طريقة لاستكشاف خواص المتصفح. الآن ماذا لو أردت التحقق من دعم المتصفح لخاصية مُعينة ثم أردت الاستعانة بالـ polyfill لجعل المتصفح يعمل بشكل أفضل؟ هذا ما يُمكنك القيام به لدى استخدامك لـ YepNope. YepNope عبارة عن أداة تحميل شرطية conditional loader، مما يعني بأنها لن تقوم بتحميل سوى السكربتات التي يحتاجها المُتصفح. تم تضمين YepNope مُباشرة ضمن Modernizr وبالتالي لا حاجة لك للتفكير أو القيام بتحميل أو الربط مع مكتبة Javascript أُخرى. لكن كيف نستعملها؟ سنقوم باستخدام Canvas كمثال هنا أيضا. يرغب المطورون عادة بدعم (القيام بـ Fallback لـ) المتصفحات التي لا تدعمها مثل IE8 أو الإصدارات السابقة له. الطريقة التقليدية للقيام بذلك هو ربط صفحة الـ HTML خاصتك بسكربت Polyfill يقوم بذلك كـ FlashCanvas مثلا: <script src="http://flashcanvas.net/bin/flashcanvas.js"></script> المشكل مع هذا الحل هو أن كل المتصفحات ستقوم بتحميل هذا السكربت، رغم أن ذلك غير مطلوب ولا فائدة تُرجى منه. هناك من يرى أن وضع السكربت في تعليق شرطي conditional comment يحل هذا المشكل، لكن إن كان بإمكاننا إبقاء السكربت خارج شفرة الصفحة بشكل كامل فسيكون ذلك أفضل بكثير، وهنا يأتي دور Modernizr.load() كما سبق ذكره فإنه تم تضمين YepNope داخل Modernizr وبالتالي فإنه من الممكن التحقق من خاصية مُعينة ومن ثم توفير Polyfill خاصة بها إن لم تكن مدعومة. تجدر الإشارة إلى أنه لا يتم تضمين ()load. بشكل قياسي في ملف development، وبالتالي فإنه يجب عليك تضمينه لدى قيامك بـ'بناء' (build) الملف. الاستعمال القاعدي للدالة ()load. يخص التحقق من خاصية مُعنية إن كانت مدعومة (yep) أو لا(nope). في المثال التالي سيقوم Modernizr بالتحقق من دعم Canvas وفي حال ما إذا لم تكن مدعومة، يقوم بتحميل FlashCanvas: Modernizr.load({ test: Modernizr.canvas, nope: 'http://flashcanvas.net/bin/flashcanvas.js' }); إن كنت تملك IE8 على جهازك، الق نظرة على لسان تبويب Network في الـ Developer tools، ستلاحظ أن المتصفح يقوم بتحميل وتهيئة flashcanvas.js. تحميل FlashCanvas في IE8 إليكم الآن مثالا أكثر فائدة والذي يقوم بالتحقق من دعم <input type="date"> ومن ثم تحميل ملفي jQuery وملف CSS لإنشاء مختار للتواريخ Data picker: <script src="modernizr.js"></script> <script>Modernizr.load({ test: Modernizr.inputtypes.date, nope: ['http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js', 'jquery-ui.css'], complete: function () { $('input[type=date]').datepicker({ dateFormat: 'yy-mm-dd' }); } }); </script> كما هو ظاهر من هذا السكربت، ستقوم الصفحة بالتحقق من دعم <input type="date">، وفي حالة ما إذا لم تكن مدعومة، ستقوم بتحميل ملفي jQuery وملف CSS (في هذا المثال يُفترض بملف CSS أن يكون محليا). بعد الفراغ من ذلك (on complete) تتم مناداة الإضافة مع كل <input type="date"> الموجودة في الـ DOM. سيتم تحميل ملفات jQuery في العديد من المتصفحات، لكنه لن يتم ذلك على Opera (أو على أحدث إصدارات Chrome). عنصر منتقي التاريخ من jQuery في متصفح فيرفوكس عنصر منتقي التاريخ الأصلي في متصفح أوبرا نعتظهر الصورتان السابقتان الاختلافات الناتجة عن تحميل المتصفح لإضافة jQuery في الأول ودعمه للخاصية في الثاني. ويظهر الأمر أيضا بشكل واضح في قائمة الملفات التي يقوم كل متصفح بتحميلها: تحميل موارد عنصر منتقي التاريخ في متصفح فيرفوكس تحميل عنصر منتقي التاريخ في متصفح أوبرا لاحظوا هنا أن المتصفح يقوم بتحميل ملفي jQuery مرتين، وهو سلوك طبيعي لمكتبة YepNope، ولذلك لا تقلق من الأمر فهو طبيعي. يُمكنك القيام بأكثر مما قُمنا به في هذين المثالين مع مكتبة YepNope. إليك المثال التالي والمأخوذ مباشرة من موقع المكتبة والذي سيتعرض كافة الخواص الممكنة لها (كل الخواص ليست مطلوبة): yepnope([{ test : /* boolean(ish) - Something truthy that you want to test */, yep : /* array (of strings) | string - The things to load if test is true */, nope : /* array (of strings) | string - The things to load if test is false */, both : /* array (of strings) | string - Load everytime (sugar) */, load : /* array (of strings) | string - Load everytime (sugar) */, callback : /* function ( testResult, key ) | object { key : fn } */, complete : /* function */ }, /* ... */ ]); الخلاصة Modernizr عبارة عن مكتبة استكشافية في غاية القوة، تسمح لك بالتحقق من إن كان المتصفح يدعم الخواص التي ترغب في استعمالها على صفحاتك، وبناء على ذلك تقوم الصفحات باستخدام تلك الخواص كما تدعمها تلك المتصفحات أو تقوم بالاستعانة بـ polyfill لتعويض النقص الناجم عن قصور المتصفح المستخدم في استعراض تلك الصفحات. قمنا في هذا المقال باستعراض كيفية إنشاء ملف Modernizr ومن ثم استخدامه بطريقتين مختلفين: استخدام كائن Modernizr بشكل مباشر (Modernizr.<featurename>) أو الاستعانة بـ YepNope. ترجمة –وبتصرف- للمقال: Using Modernizr to detect HTML5 features and provide fallbacks لصاحبه: Tom Leadbetter1 نقطة
-
أعمل على مشروع كبير وأقوم بالعديد من التعديلات عليه مع مطورين آخرين هل يوجد أداة ما تساعدني على إدارة الإصدار المختلفة منه والتبديل بينهم؟ وأيضا عمل فرع خاص بالميزات وهكذا.. وجدت أداة Git ولكن ماهي وكيف أستخدمها وماعلاقتها ب devops1 نقطة
-
كما ذكر الأخ وائل يمكنك تطوير موقع ثم تطوير تطبيق لكن في رأيي أسرع طريقة لتحقيق ذلك هي تطوير الموقع وجعله progressive webapp وهذا يعني أن المستخدم لما يدخل للموقع سيتم سؤاله اذا أراد تثبيت الموقع كتطبيق على الهاتف او الحاسوب1 نقطة
-
أريد إنشاء نسخة مستقلة من الصورة (بشكل مشابه للدالة cv::clone في cpp) لأقوم ببعض التعديلات عليها (لكي لا تتأثر النسخة الأصلية من الصورة).1 نقطة
-
1 نقطة
-
ممكن مساعدة، أريد دالة يمكن تمرير قيمة لها وهذه القيمة عبارة مصفوفة من الأعداد ثم تقوم بإرجاع مجموع أكبر ثلاث اعداد في المصفوفة. ليكن اسم الدالة عبارة عن sumThreeNumbers1 نقطة
-
يمكنك استخدام split و foreach و startsWith لتحقيق المطلوب function getWords(text) { console.log(text); let result = [];//قائمة لحفظ الكلمات المراد ارجاعها let words = text.split(' ');//تحويل النص لمصفوفة عبارة عن الكلمات المتواجدة في المصفوفة المفصولة بفراغ console.log(words); words.forEach((word) => {// استخدام حلقة التكرار لجلب كل كلمة على حدى if (word.startsWith('a') || word.startsWith('b')) {//التأكد من ان الكلمة تبدأ ب الحروف المرغوبة result.push(word); //اذا كانت الكلمة تبدأ بالحروف المرغوبة نضيفها لقائمة النتيجة } }); console.log(result); return result; // ارجاع النتيجة في الاخير } getWords('hello its a gread day body'); الاخراج سيكون كالتالي hello its a gread day body //النص [ 'hello', 'its', 'a', 'gread', 'day', 'body' ] // النص بعد تحويله لقائمة [ 'a', 'body' ] // النتيجة1 نقطة
-
قمت برسم الأشكال ال 4 التالية وأريد وضع عنوان عام لهذه ال subplots فكيف نقوم بذلك؟ # Implementation of matplotlib function import numpy as np import matplotlib.pyplot as plt # First create some toy data: x = np.linspace(0, 1.5 * np.pi, 100) y = np.sin(x**2)+np.cos(x**2) fig, axs = plt.subplots(2, 2, subplot_kw = dict(polar = True)) axs[0, 0].plot(x, y) axs[1, 1].scatter(x, y) plt.show()1 نقطة
-
شكرا ع المساعدة يوجد سؤال اخر ممكن التوضيح بعد اذنك أكتب دالة يمكن تمرير قيمة لها وهذه القيمة عبارة نص مكون من مجموعة من الكلمات ثم تقوم بإرجاع مصفوفة تحتوي على كل الكلمات التي تبدأ بحرف “A “أو حرف “B.“ ليكن اسم الدالة عبارة عن getWords استخدم التعريف التالي: function getWords (text) {}1 نقطة
-
يمكنك أن تقوم بهذا من خلال عمل دالة getMaxThree والتالي تقوم بالبحث في المصفوفة وتُرجع أكبر ثلاثة أرقام فيها: var numbersArray = [93, 17, 91, 91, 98, 33, 9, 38, 55, 78, 29, 81, 60, 91]; function getMaxThree(numbersArray) { // إرجاع المصفوفة كما هي إن كانت تحتوي على أقل من ثلاث قيم if (numbersArray.length <= 3) return numbersArray; // القائمة ستحتوي على أول ثلاث عناصر في المصفوفة بشكل إفتراضي // سوف نقوم بتغير محتوياتها فيما بعد let max = [numbersArray[0], numbersArray[1], numbersArray[2]]; max.sort((a, b) => a - b); // ترتيب المصفوفة تصاعديًا // في الحلقة التالية نقوم بالمرور على عناصر القائمة بالكامل (ماعد أول ثلاث عناصر ولذلك بدأ العد من 3) for (let i = 3; i < numbersArray.length; i++) { // لو كان العنصر أكبر من قيمة أول عنصر في المصفوفة max سوف يتم تبديله // ثم نعيد ترتيب المصفوفة مرة أخرى if (numbersArray[i] > max[0]) { max[0] = numbersArray[i]; max.sort((a, b) => a - b); } } return max; } result = getMaxThree(numbersArray); console.log("the three largest values are:"); console.log(result); بعد ذلك يمكنك أن تستخدم التابع reduce لحساب مجموع المصفوفة result كالتالي: sum = result.reduce((total, ele) => total + ele, 0); console.log("the total of the three largest values is:"); console.log(sum); تستطيع أيضًا عمل دالة sumThreeNumbers والتالي تقوم بإستدعاء الدالة getMaxThree وحساب المجموع وإعادته كالتالي: function sumThreeNumbers(numbersArray) { result = getMaxThree(numbersArray); // الحصول على أكبر ثلاث أرقام من المصفوفة return result.reduce((total, ele) => total + ele, 0); // جمع قيمة الأرقام الثلاثة } ملاحظة: يمكنك أيضًا أن تستخدم حلقة تكرار لحساب مجموع المصفوفة بدلًا من التابع reduce، كالتالي: function sumThreeNumbers(numbersArray) { result = getMaxThree(numbersArray); sum = 0; for (let i = 0; i<result.length; i++) { sum += result[i]; } return sum; } هنا شكل الكود النهائي: function getMaxThree(numbersArray) { // إرجاع المصفوفة كما هي إن كانت تحتوي على أقل من ثلاث قيم if (numbersArray.length <= 3) return numbersArray; // القائمة ستحتوي على أول ثلاث عناصر في المصفوفة بشكل إفتراضي // سوف نقوم بتغير محتوياتها فيما بعد let max = [numbersArray[0], numbersArray[1], numbersArray[2]]; max.sort((a, b) => a - b); // ترتيب المصفوفة تصاعديًا // في الحلقة التالية نقوم بالمرور على عناصر القائمة بالكامل (ماعد أول ثلاث عناصر ولذلك بدأ العد من 3) for (let i = 3; i < numbersArray.length; i++) { // لو كان العنصر أكبر من قيمة أول عنصر في المصفوفة max سوف يتم تبديله // ثم نعيد ترتيب المصفوفة مرة أخرى if (numbersArray[i] > max[0]) { max[0] = numbersArray[i]; max.sort((a, b) => a - b); } } return max; } function sumThreeNumbers(numbersArray) { result = getMaxThree(numbersArray); return result.reduce((total, ele) => total + ele, 0); } //------------ var numbersArray = [93, 17, 91, 91, 98, 33, 9, 38, 55, 78, 29, 81, 60, 91]; console.log(sumThreeNumbers(numbersArray));1 نقطة
-
يمكنك استخدام set_facecolor(color) للتحكم بألوان أي axes لديك لكن يجب أن تكون دقيقاُ في استخدامها، فمثلاً لتغيير لون الخلفية في مثالك نقوم بأخذ كائن يمثل ال axes (المساحة التي تظهر فيها الصورة) الخاص بك ثم نستدعي منه الدالة كالتالي: import numpy as np import matplotlib.pyplot as plt x = np.random.normal(1, 2, 5000) y = np.random.normal(-1, 3, 2000) bins = np.linspace(-10, 10, 30) # الخاص بك axes أخذ غرض يمثل ال ax = plt.axes() ax.set_facecolor('black') # هنا فقط لإضافة خطوط شبكة للرسم أي يمكنك تجاهلها ax.grid(b = True, color ='w', linestyle ='-.', linewidth = 0.5, alpha = 0.6) plt.hist([x,y], bins = 15,label=[x,y],color=["red","blue"]) legend = ['Data1','Data2'] plt.legend(legend) plt.show() الخرج: أما ماتقوم به أنت هو تلوين ال figure الذي يحتوي ال axes، فكما نعلم أن ال figure يحتوي ال axes (واحد أو أكثر) انظر للصورة لتفهم ما أقصد: حيث قمت بأخذ كائن يمثل ال figure ثم قمت بضبط لونه، فظهر بذلك الشكل. وكحل آخر يمكنك استخدام rcParams كالتالي: import matplotlib.pyplot as plt plt.rcParams['axes.facecolor'] = 'black'1 نقطة
-
يمكنك الآن تطبيق الفكرتين من خلال السؤالين: كيفية عمل اشعار في وقت محدد: كيفية حساب المدة الزمنية لتاريخ معين: إذا قمتي بقراءة الإجابتين بشكل جيد أضمن لك أنك ستستطيعين برمجة الحل. يمكن المساعدة بأسئلة محددة خلال تطبيقك للفكرة البرمجية في حال لم تعمل لاحقاً عليك الآن التجريب1 نقطة
-
رغم أنني لم أنجز بعد أي مشروع عملي بـ Ruby وما زلت مكتفيا في كل مشاريعي بالبرمجة بـ PHP، إلا أنني منذ ألقيت أول نظرة على لغة البرمجة روبي، سنة 2008، وأنا معجب بها بفضل ما تتميز به من سلاسة وقوة وما تضفيه على البرمجة من متعة. أما سبب عدم اعتمادي عليها حتى الآن في مشروع ما هو أنني لم أحتجها بعد بشكل جدي، فغالبا ما أنجز ما أريد بشكل سريع بواسطة PHP، خاصة أنه على مستوى المواقع الصغيرة، يبقى الحصول على استضافة المواقع المبرمجة بـ PHP أسهل وأرخص. كما هي العادة؛ الحاجة أم الاختراع. كان يوكيهيرو ماتسوموتو (Yukihiro Matsumoto) يبحث عن لغة برمجة تزيد من إنتاجيته، لغة تجعله يستمتع بالبرمجة. لم يجد، فبدأ التفكير في إبداع لغة برمجية جديدة سنة 1993 سماها روبي Ruby وأطلق أول نسخة عامة منها شهر ديسمبر 1995. استفادت روبي من مميزات لغات برمجة أخرى وأتت بمفاهيم جديدة لترفع من إنتاجية المبرمجين وتشعرهم بمتعة البرمجة، فحققت اللغة بذلك نجاحا كبيرا في اليابان، لكنها رغم ذلك، وبسبب عدم ترجمة وثائقها إلى الانجليزية، لم تستطع إثارة اهتمام المبرمجين من خارج اليابان إلا سنة 2000، واحتاجت بعد ذلك لخمس سنوات أخرى قبل أن تصبح ظاهرة عالمية بعد أن جاء المبرمج الدنماركي دافيد هاينماير هانسون، سنة 2005، بإبداعه الذي غير الكثير من مفاهيم تطوير مواقع وخدمات الويب؛ إطار العمل البرمجي روبي أون ريلز Ruby On Rails. يقول يوكيهيرو ماتسوموتو أن لغة روبي مصممة للإنتاجية وللمرح، وهي تركز على احتياجات الإنسان، وليس جهاز الكمبيوتر: «الناس في كثير من الأحيان، ولا سيما مهندسو الحاسب الآلي، يكون تركيزهم على الكمبيوتر. إنهم يعتقدون، "من خلال القيام بذلك، فإن الجهاز سوف يعمل بشكل أسرع. من خلال ذلك، فإن الجهاز يعمل بفعالية أكثر. من خلال ذلك، فإن الجهاز سيكون ويكون ويكون" ولكن في الحقيقة نحن بحاجة إلى التركيز على البشر وعلى كيفية كتابة وفهمنا للبرامج أو تطبيقات تعمل على الجهاز. نحن السادة (البشر). هم العبيد (الجهاز).» لذلك فإن تعابير اللغة بسيطة، سهلة الفهم وأكثر إنسانية. النتيجة دائما: نصوص برمجية أنيقة، سهلة القراءة والفهم. مع متعة بلا حدود خلال البرمجة. أفضل المصادر لتعلم روبي يمكنني أن أقول بأنني قرأت الكثير من كتب التقنية والبرمجة، عن لغات برمجة مختلفة، لكتاب مختلفين ومن ناشرين مختلفين. لكن أفضل كتاب -على الإطلاق- لشرح وتعليم لغة برمجية كان كتاب ”Beginning Ruby: From Novice to Professional“، يبدأ من البدايات؛ يشرح المفاهيم الأساسية ثم يتعمق تدريجيا حتى ينقلك من مستوى المبتدئين إلى مستوى المحترفين، بأسلوب سهل وممتع. بالنسبة إليّ، لو كتب المؤلف (Peter Cooper) أي كتاب آخر، حول التقنية أو البرمجة، فإني حتما سأشتريه مهما يكن موضوعه. هو شخص مبدع ونشيط في المجال التقني، وهو يحرر نشرة بريدية أسبوعية عن روبي، يجمع فيها أهم الأخبار، المقالات التعليمية وجديد المكتبات البرمجية الخاصة بروبي. بعد هذا الكتاب، يمكنك الانتقال إلى كتاب Programming Ruby 1.9 & 2.0 الذي يغوص عميقا في تفاصيل اللغة ويشرح وحداتها البرمجية الرئيسية جميعها. هذا الكتاب عبارة عن دليل مرجعي (reference manual) يمكنك العودة إليه في أي وقت تحتاج إلى الإلمام بتفصيلة معينة خاصة باللغة، ولا حاجة لقراءته كاملا من الغلاف إلى الغلاف. تزخر المكتبة البرمجية بكثير من الكتب التي تشرح لغة البرمجة روبي، لكن هاذين الكتابين يكفيان تماما لنقلك من مستوى المبرمج المبتدئ إلى الخبير المتمكن من كل تفاصيل روبي. لا حاجة لك لأن تقرأ كتبا أخرى. يمكنك قراءة وثائق المساعدة في الموقع الرسمي، ومتابعة النشرة البريدية، التي يحررها بيتر كوبر، لتبقى على إطلاع على أخبار اللغة وأبرز ما يكتب عنها. أفضل المصادر لتعلم روبي أون ريلز لا شك أن الفضل في الانتشار العالمي لروبي يعود إلى الإطار البرمجي Ruby On Rails، الذي أحدث ثورة في مجال تطوير تطبيقات الويب خلال فترة الفورة التي عرفتها تطبيقات ويب 2.0، حيث ساعد الإطار كل من لديه فكرة ما، وقدرة على تعلم البرمجة -ولو قليلا- على تنفيذ الفكرة بسرعة كبيرة وإطلاق الموقع للاستخدام خلال أيام أو أسابيع معدودة. إذا أردت أن تلقي نظرة سريعة على إطار ريلز، وتعلمه لتنفيذ مشروع صغير، فلن تجد أفضل من كتاب ”Ruby on Rails Tutorial: Learn Web Development with Rails“، الذي يقدم كل ما يحتاج إليه الوافد الجديد لعالم ريلز، من تثبيت النظام إلى رفع الموقع إلى الإنترنت. الكتاب متوفر للقراءة مجانا من الإنترنت. أو يمكنك الاكتفاء بالدليل التعليمي المقدم من فريق ريلز Rails Guides. حين تحتاج إلى تعميق معرفتك بريلز، أو تحترف البرمجة به، فإن الكتاب الأفضل هو ”Agile Web Development with Rails“، الذي كان أول وأفضل كتاب يصدر عن ريلز، ولعله ما يزال الأفضل. يبدأ الكتاب مباشرة بنموذج عملي لبناء تطبيق ويب، خطوة بخطوة مع شرح كاف لكل مرحلة. ثم في الجزء الثاني من الكتاب ينقلك لتتعمق أكثر في التفاصيل الدقيقة. خلافا للكتب التي نوهت عنها هنا تتوفر عدد من الدروس المرئية لكل من ريلز وروبي، إضافة إلى كثير من المقالات التعليمية. لكني لم أطلع عليها، فأنا بالأساس من هواة التعلم من الكتب، لذلك لم أذكر تلك المصادر واكتفيت بذكر الكتب، التي أراها الأفضل على الإطلاق. تحديثات: 14/08/2017: تم تحديث روابط الكتب لآخر الإصدارات 04/03/2018: تقدم أكاديمية حسوب دورة شاملة لتعلم تطوير تطبيقات الويب باستخدام لغة Ruby1 نقطة
-
هل تعاني من صعوبة في تطبيق مفاهيم البرمجة الكائنية مع لغة JavaScript؟ إذًا أنت في المكان الصحيح، ففي هذا المقال سنبدأ بمطلع لمفاهيم البرمجة الكائنية (أو الشيئية كما قد يُطلق عليها البعض)، ومن ثم مراجعة نموذج جافا سكريبت في الكائنات، وأخيرًا شرح مفاهيم البرمجة الكائنية في جافا سكريبت، لتحصل على إلمام واف والقصة الكاملة. مراجعة في جافاسكريبت JavaScript يُمكن العودة إلى المقال إعادة تقديم JavaScript لمن أساء فهمها هنا في أكاديمية حسوب للحصول على مراجعة لأساسيات لغة جافا سكريبت وأخذ فكرة عن المغيرات وأنواع الدوال وبقية الأساسيات. البرمجة الكائنية Object-oriented programming إن البرمجة الكائنية (OOP) ما هي إلا نمط برمجي يَستخدم التجريد في إنشاء نماذج/نسخ لتجسيد العالم الحقيقي، وتَستخدم البرمجة الكائنية في ذلك أساليب مُتعدّدة من هذا النمط، فهي تستخدم الوحدات module، وتعدديّة الأشكال polymorphism والتغليف encapsulation، وتجدر الإشارة إلى أن معظم لغات البرمجة تدعم مفهوم OOP أمثال اللغات البرمجية: جافا، بايثون، روبي، وطبعًا جافا سكريبت. يُعالج أو لنقل يَتصور مفهوم البرمجة الكائنية OOP البرنامج كتشكيلة من الأشياء/الكائنات المتعاونة/المترابطة بدلًا من يتصوّره كتشكيلة من الدوال (functions) أو كسرد من الأوامر. ففي مفهوم OOP، كل كائن/شيء له القدرة على استقبال الرسائل، ومعالجة البيانات، وإرسال الرسائل إلى باقي الكائنات، ويُمكن اعتبار أنه لكل كائن object كينونة خاصة به ودور/وظيفة مستقلة عن الكائن الآخر. تُعزز البرمجة الكائنية القدرة على صيانة الشيفرة البرمجية والمرونة في التطوير، وأثبتت جدارتها على نطاق واسع في هندسة البرمجيات الكبيرة، ولأن البرمجة الكائنية تُشدد على استخدام الوحدات module، فإن الشيفرة/الكود المكتوب بمفهوم البرمجة الكائنية هو أبسط في التطوير وأسهل في الفهم مستقبلًا (عند التنقيح والتعديل)، وكما يعزز مفهوم البرمجة الكائنية التحليل المباشر للشيفرة، وفهم الحالات الشائكة فهمًا أفضل من باقي الأساليب البرمجية الأخرى. مصطلحات البرمجة الكائنية المجال في البرمجة الكائنية Namespace ما هو إلا عبارة عن حاوي تسمح للمطوّر بتحزيم جميع الوظائف تحت اسم محدد وفريد. الصنف أو الفئة Class في البرمجة الكائنية يعتني الصنف بكل ما يتعلّق بميزات وخصائص الكائن، والصنف ما هو إلا قالب template تعريفي بخاصيات properties وبطُرق/وظائف methods الكائن object. الكائن Object في البرمجة الكائنية الكائن ما هو إلا حالة/أمثولة instance من صنف class. الخاصية property في البرمجة الكائنية ما هي إلا مميزات وخصائص الكائن، كاللون مثلًا. الطريقة أو الوظيفة Method في البرمجة الكائنية تعتني الطريقة أو الوظيفة كما يُسميها البعض بقدرات الكائن، مثل قدرة المشي مثلًا، وهي دور أو وظيفة مرتبطة مع صنف class. المشيد Constructor في البرمجة الكائنية ما هو إلا طريقة method تُستدعى في لحظة استهلال instantiate الكائن، وعادةً ما يكون له نفس اسم الصنف الذي يحتويه. الوراثة Inheritance في البرمجة الكائنية يُمكن للصنف أن يرث مميزات من صنف آخر. التغليف Encapsulation في البرمجة الكائنية طريقة في تحزيم البيانات data والطُرق methods التي تستخدم البيانات. التجريد Abstraction في البرمجة الكائنية يجب على الاقتران الحاصل من: الوراثة والطُرق methods والخاصيات properties لكائن معقد وشائك التمثيل برمجيًا أن يعكس الواقع المراد محاكاته في البرمجة الكائنية. تعددية الأشكال Polymorphism في البرمجة الكائنية تحمل كلمة Poly بحد ذاتها المعنى "متعدد" وتحمل الكلمة morphism المعنى "أشكال، ويُشير المفهوم ككل إلى أن أكثر من صنف قد يُعرّف نفس الطريقة method أو الخاصية property. البرمجة المعتمدة على النموذج الأولي Prototype البرمجة المعتمدة على النموذج الأوّلي (Prototype-based programming) ما هي إلا نموذج من البرمجة الكائنية OOP ولكنها لا تستخدم الأصناف classes، بل تقوم أولًا بإعداد سلوك أي صنف class ما ومن ثم تُعيد استخدامه، ويُطلق البعض على هذا النموذج: البرمجة بلا أصناف classless، أو البرمجة المَبْدَئِية المنحى prototype-oriented، أو البرمجة المعتمدة على الأمثولة instance-based). يعود أصل اللغة المعتمدة على النموذج الأولي إلى لغة Self، والتي طوّرها David Ungar وRandall Smith، ولكن أسلوب البرمجة بدون أصناف class-less توسّع ونال شهرة كبيرة في العقد الأخير، واُعتمد من قبل العديد من اللغات البرمجية أشهرهم جافا سكريبت. البرمجة الكائنية باستخدام جافا سكريبت المجال Namespace في جافا سكريبت المجال هو أشبه بمستوعب/بحاوية (container) تسمح للمطوّر في تحزيم وظائف تحت اسم فريد، أو اسم تطبيق محدد، ففي جافا سكريبت المجال هو مجرد كائن object كأي كائن آخر يحتوي على طُرق methods، وخاصيات properties، وحتى كائنات objects. ملاحظة هامة: من المهم جدًا الانتباه إلى أنه في جافا سكريبت، لا يوجد فرق بين الكائنات العادية والمجالات namespaces، وهذا يختلف عن اللغات الكائنية الأخرى، الأمر الذي قد يُربك المبرمجين المبتدئين في جافا سكريبت. إن إنشاء مجال namespace في جافا سكريبت بسيطٌ للغاية، فمن خلال إنشاء كائن عام/مشترك/شامل global، ستصبح جميع المُتغيّرات variables والطرق methods، والدوال functions خاصياتٍ لهذا الكائن، ويٌقلل استخدام المجالات namespaces أيضًا من احتمالية تضارب الأسماء في التطبيق، منذ أن كل كائن من كائنات التطبيق ما هي إلى خاصيات كائن شامل/عام معرّفة على مستوى التطبيق. سيُنشئ في الخطوة التالية كائنًا عامًا global وبالاسم MYAPP: // global namespace var MYAPP = MYAPP || {}; يُظهر المثال السابق، كيف تم التأكّد أولًا فيما إذا كان MYAPP معرفًا (سواء في نفس الملف أو في آخر)، ففي حال الإيجاب سيُستخدم الكائن العام MYAPP، وفي حال عدم تعريفه مُسبقًا سيُنشئ كائنًا خالٍ وبالاسم MYAPP والذي سيغلّف encapsulate الطرق methods والدوال functions والمتغيرات variables والكائنات objects. كما يُمكن أيضًا إنشاء مجال فرعي sub-namespaces: // sub namespace MYAPP.event = {}; يوضّح المثال التالي الصيغة المستخدمة في إنشاء مجال namespace وإضافة متغيرات ودوال: // Create container called MYAPP.commonMethod for common method and properties MYAPP.commonMethod = { regExForName: "", // define regex for name validation regExForPhone: "", // define regex for phone no validation validateName: function(name){ // Do something with name, you can access regExForName variable // using "this.regExForName" }, validatePhoneNo: function(phoneNo){ // do something with phone number } } // Object together with the method declarations MYAPP.event = { addListener: function(el, type, fn) { // code stuff }, removeListener: function(el, type, fn) { // code stuff }, getEvent: function(e) { // code stuff } // Can add another method and properties } // Syntax for Using addListener method: MYAPP.event.addListener("yourel", "type", callback); الكائنات الأساسية/القياسية المبنية داخل لغة جافا سكريبت Standard built-in objects تتضمن لغة جافا سكريبت العديد من الكائنات في تركيبتها، على سبيل المثال، يوجد كائنات مثل Math، Object، Array، String، ويُظهر المثال التالي كيفيّة استخدام الكائن Math للحصول على رقم عشوائي باستخدام أحد طُرق method هذا الكائن وهي الطريقة ()random. console.log(Math.random()); ملاحظة: يَفترض المثال السابق وجميع الأمثلة التالية في المقال وجود دالة function بالاسم ()console.log معرّفة تعريفًا عامًا (globally)، مع العلم أن هذه الدالة ليست جزء من اللغة نفسها، ولكنها دالة متوفّرة في العديد من متصفحات الإنترنت لأغراض تشخيص الشيفرة البرمجية debugging. يُمكن العودة إلى مرجع لغة جافا سكريبت: الكائنات الأصلية المعيارية للحصول على قائمة بالكائنات المبينة داخل لغة جافا سكريبت نفسها. كل كائن في جافا سكريبت هو حالة/أمثولة instance من الكائن Object ويَرث كافة خاصياته properties وطُرقه methods. الكائنات المخصصة Custom objects في جافا سكريبت الصنف/الفئة The class لغة جافا سكريبت لغة من النوع prototype-based ولا تحتوي على العبارة class كما هو حال باقي لغات البرمجة الكائنية، كما في روبي أو بايثون، ويُربك هذا الأمر المبرمجين المعتادين على اللغات التي تعتمد على هذه العبارة أو المفهوم، وتستخدم جافا سكريبت بدلًا من ذلك الدوال functions لمحاكات مفهوم الأصناف classes، وتعريف صنف هو بسهولة تعريف أي دالّة: var Person = function () {}; الكائن (أمثولة الصنف class instance) يتطلب إنشاء حالة/أمثولة instance جديدة من كائن obj استخدام العبارة new obj، وتعيين النتيجة إلى متغيّر بغرض الوصول إلى فيما بعد. عُرّف في الشيفرة السابقة صنف class بالاسم Person، وفي الشيفرة التالية، سيُنشئ حالتين/أمثولتين instances من هذا الصنف، الأولى بالاسم person1 والثانية بالاسم person2. var person1 = new Person(); var person2 = new Person(); المشيد The constructor يُستدعى المُشيّد constructor في لحظة الاستهلال instantiation (اللحظة التي يُنشئ فيها الكائن)، والمُشيّد ما هو إلا طريقة method من طُرق الصنف class، وفي جافا سكريبت تعمل الدالة على تشييد الكائن، ولذلك لا داعي إلى تعريف طريقة method من أجل عميلة التشييد، وكل إجراء مصرّح في الصنف class يُنفّذ في لحظة الاستهلال instantiation. يُستخدم المُشيّد في تعيين خاصيات properties الكائن، أو في استدعاء طُرق methods معينة لتحضير الكائن للاستخدام، وأما إضافة طُرق صنف وتعريفها يحدث باستخدام صيغة syntax مختلفة سنتطرّق إليها فيما بعد خلال المقال. تُظهر الشيفرة التالية كيف يُسجّل log (يُرسل رسالة نصية إلى طرفية المتصفح console) مُشيّد الصنف Person رسالة نصية حينما يُستهل instantiated. var Person = function () { console.log('instance created'); }; var person1 = new Person(); var person2 = new Person(); الخاصية The property (خاصية الكائن object attribute) الخاصيات properties ما هي إلا متغيرات محتوات في الصنف class، وكل حالة/أمثولة من الكائن تمتلك هذه الخاصيات، وتُعيّن الخاصيات في دالة مُشيّد الصنف بحيثُ تُنشئ مع كل حالة/أمثولة instance. إن الكلمة المفتاحية this، والتي تُشير إلى الكائن الحالي، تسمح للمطوّر بالعمل مع الخاصيات من ضمن الصنف، والوصول (قراءةً وكتابةً) إلى الخاصية property من خارج الصنف يكون من خلال الصيغة InstanceName.Property كما هو الأمر في لغة C++ (سي بلس بلس) وJava والعديد من اللغات الأخرى، ومن داخل الصنف تُستخدم الصيغة this.Property للحصول على قيمة الخاصية أو لتعيين قيمتها. في الشيفرة التالية، عُرّفت الخاصية firstName للصنف Person وفي لحظة الاستهلال instantiation: var Person = function (firstName) { this.firstName = firstName; console.log('Person instantiated'); }; var person1 = new Person('Alice'); var person2 = new Person('Bob'); // Show the firstName properties of the objects console.log('person1 is ' + person1.firstName); // logs "person1 is Alice" console.log('person2 is ' + person2.firstName); // logs "person2 is Bob" الطرق The methods الطرق methods ما هي إلا دوال (وتُعرّف كما تعرّف الدوال functions)، فيما عدا ذلك فهي تُشبه الخاصيات properties، واستدعاء طريقة method مشابه إلى الوصول إلى خاصيّة ما، ولكن مع إضافة () في نهاية اسم الطريقة، وربما مع مُعطيات arguments، ولتعريف طريقة، تُعيّن دالة إلى خاصيّة مُسمّات من خاصيّة الصنف prototype، ويُمكن فيما بعد استدعاء الطريقة على الكائن بنفس الاسم الذي عُيّن للدالة. في الشيفرة التالية، عُرّفت ومن ثم اُستخدِمت الطريقة ()sayHello للصنف Person. var Person = function (firstName) { this.firstName = firstName; }; Person.prototype.sayHello = function() { console.log("Hello, I'm " + this.firstName); }; var person1 = new Person("Alice"); var person2 = new Person("Bob"); // call the Person sayHello method. person1.sayHello(); // logs "Hello, I'm Alice" person2.sayHello(); // logs "Hello, I'm Bob" إن الطُرق methods في جافا سكريبت ما هي إلا دالة كائن عادية مرتبطة مع كائن كخاصية property، وهذا يعني أنه يُمكن استدعاء الطُرق خارج السياق، كما في المثال التالي: var Person = function (firstName) { this.firstName = firstName; }; Person.prototype.sayHello = function() { console.log("Hello, I'm " + this.firstName); }; var person1 = new Person("Alice"); var person2 = new Person("Bob"); var helloFunction = person1.sayHello; // logs "Hello, I'm Alice" person1.sayHello(); // logs "Hello, I'm Bob" person2.sayHello(); // logs "Hello, I'm undefined" (or fails // with a TypeError in strict mode) helloFunction(); // logs true console.log(helloFunction === person1.sayHello); // logs true console.log(helloFunction === Person.prototype.sayHello); // logs "Hello, I'm Alice" helloFunction.call(person1); كما يُظهر المثال السابق، جميع الإحالات المستخدمة في استدعاء الدالة sayHello تُشير إلى نفس الدالة سواءً الاستدعاء الحاصل مع person1 أو Person.prototype أو حتى في المتغيّر helloFunction وقيمة this خلال استدعاء الدالة يعتمد على الكيفية التي تُستدعى فيها، حيث تُشير الكلمة المفتاحية this إلى الكائن الحالي الذي تُستدعى عليه الطريقة method، بمعنى عندما تم استدعاء الطريقة ()sayHello على الكائن person1 فإن this تُشير إلى الكائن person1، وعند استدعاء sayHello على الكائن person2 فإن this تُشير إلى الكائن person2، ولكن إن تم الاستدعاء بطريقة مختلفة، فإن this ستُعيّن تعينًا مختلفًا، فاستدعاء this من المتغيّر (كما في ()helloFunction) سيُعيّن this إلى الكائن العام global (والذي سيكون window في متصفح الإنترنت)، ومنذ أن هذا الكائن (على الأغلب) لا يملك الخاصّيّة firstName، ستكون النتيجة كما هو الحال في المثال السابق “Hello, I’m undefined”، كما يمكن دائمًا تعيين this صراحةً باستخدام Function#call (أو Function#apply) وهو كما كان في نهاية المثال. الوراثة تُستخدم الوراثة في جافا سكريبت في إنشاء صنف class كمثيل مخصص لصنف أو أكثر (تدعم جافا سكريبت وراثة وحيدة فقط single inheritance)، ويُطلق على الصنف المخصص عادةً ابن (child)، ويطلق على الصنف الآخر عادةً الأب (parent)، وفي جافا سكريبت يتمّ ذلك من خلال إسناد حالة/أمثولة من الصنف الأب إلى الصنف الابن، ومن ثم تخصيصه، وفي متصفحات الإنترنت الحديثة يُمكن استخدام Object.create في تحقيق الوراثة inheritance أيضًا. ملاحظة: لا تتفقد جافا سكريبت مُشيّد صنف الابن prototype.constructor (راجع Object.prototype)، وعليه يجب التصريح عن ذلك يدويًا، لمزيد من التفصيل راجع السؤال التالي على Stackoverflow. عُرّف في الشيفرة التالية الصنف Student كصنف ابن للصنف Person، ومن ثم أُعيد تعريف الطريقة ()sayHello وأُضيفت الطريقة ()sayGoodBye علاوة على ذلك. // Define the Person constructor var Person = function(firstName) { this.firstName = firstName; }; // Add a couple of methods to Person.prototype Person.prototype.walk = function(){ console.log("I am walking!"); }; Person.prototype.sayHello = function(){ console.log("Hello, I'm " + this.firstName); }; // Define the Student constructor function Student(firstName, subject) { // Call the parent constructor, making sure (using Function#call) // that "this" is set correctly during the call Person.call(this, firstName); // Initialize our Student-specific properties this.subject = subject; }; // Create a Student.prototype object that inherits from Person.prototype. // Note: A common error here is to use "new Person()" to create the // Student.prototype. That's incorrect for several reasons, not least // that we don't have anything to give Person for the "firstName" // argument. The correct place to call Person is above, where we call // it from Student. Student.prototype = Object.create(Person.prototype); // See note below // Set the "constructor" property to refer to Student Student.prototype.constructor = Student; // Replace the "sayHello" method Student.prototype.sayHello = function(){ console.log("Hello, I'm " + this.firstName + ". I'm studying " + this.subject + "."); }; // Add a "sayGoodBye" method Student.prototype.sayGoodBye = function(){ console.log("Goodbye!"); }; // Example usage: var student1 = new Student("Janet", "Applied Physics"); student1.sayHello(); // "Hello, I'm Janet. I'm studying Applied Physics." student1.walk(); // "I am walking!" student1.sayGoodBye(); // "Goodbye!" // Check that instanceof works correctly console.log(student1 instanceof Person); // true console.log(student1 instanceof Student); // true فيما يخص السطر ;(Student.prototype = Object.create(Person.prototype في الإصدارات القديمة من جافا سكريبت والتي لا تدعم Object.create يمكن إما استخدام بعض الحيل في خداع المتصفحات –هذه الخدع معروفة إما بالاسم polyfill أو shim—أو استخدام دالة تحقق نفس النتيجة كما في المثال التالي: function createObject(proto) { function ctor() { } ctor.prototype = proto; return new ctor(); } // Usage: Student.prototype = createObject(Person.prototype); التأكّد من أن this تُشير إلى الكائن المطلوب بغض النظر عن كيف للكائن أن يُستهل يمكن أن يكون صعبًا، ومع ذلك يوجد صياغة أبسط من شأنها أن تسهّل الأمر. var Person = function(firstName) { if (this instanceof Person) { this.firstName = firstName; } else { return new Person(firstName); } } التغليف Encapsulation ليس بالضرورة أن يعلم الصنف Student كيف تمّ تنفيذ/تعريف الطريقة ()walk للصنف Person لكي يستطيع استخدام تلك الطريقة، ولا يحتاج الصنف Student إلى تعريف تلك الطريقة صراحةً إلا إذا كان المطلوب التعديل عليها، ويُطلق على هذا الإجراء مفهوم التغليف encapsulation، والذي فيه يَحزم كل صنف البيانات والطُرق methods داخل وحدة/كينونة وحيدة. إخفاء المعلومات سمة شائعة في باقي اللغات البرمجية وعادةً ما توجد كخاصيات/كطُرق إما بالاسم private أو protected، وعلى الرغم من أنه يُمكن مماثلة/محاكاة ذات الأمر في جافا سكريبت، إلا أن هذا الأمر ليس مطلبًا من متطلبات البرمجة الكائنية. التجريد Abstraction التجرير ما هو إلا ميكانيكية تسمح للمطوّر في تجسيد جانب من المشكلة التي يُعمل عليها، إما من خلال الوراثة inheritance (التخصيص specialization) أو التركيب composition، وتُحقق جافا سكريبت التخصيص من خلال الوراثة، والتركيب من خلال السماح لحالات/أمثولات الصنف لتكون قيمًا لخاصيات attributes الكائنات الأخرى. الصنف Function في جافا سكريبت يرث من الصنف Object (وهذا يوضّح التخصيص في هذا النموذج) والخاصية Function.prototype ما هي إلا حالة/أمثولة من الصنف Object (وهذا يوضّح جزئية التركيب composition). var foo = function () {}; // logs "foo is a Function: true" console.log('foo is a Function: ' + (foo instanceof Function)); // logs "foo.prototype is an Object: true" console.log('foo.prototype is an Object: ' + (foo.prototype instanceof Object)); تعددية الأشكال Polymorphism كما أن جميع الطُرق methods والخاصيات properties معرّفة ضمن الخاصية prototype، فيُمكن لبقية الأصناف أن تُعرِّف طُرقًا methods بنفس الاسم، وستكون الطُرق في نطاق الصنف الذي عُرفت به، إلا إذا كان الصنفان على علاقة من نوع أب وابن parent-child، بمعنى آخر أحد الصنفان يرث من الآخر خاتمة إن الأساليب التي تم التطرُّق إليها ليست الأساليب الوحيدة التي يمكن استخدامها في تطبيق مفاهيم البرمجة الكائنية في جافا سكريبت، والتي هي مرنة إلى حد كبير في هذا الصدد، ولم تلجئ إلى أي خدع في تطبيق هذه المفاهيم، ولم تقلّد أيضًا الأساليب والنظريات المستخدمة في اللغات الأخرى، وفي جعبة جافا سكريبت العديد من الأساليب الأخرى لتطبيق مفاهيم متقدمة في البرمجة الكائنية التوجّه، ولكن هذه الأساليب المتقدمة هي خارج إطار مقالة تمهيدية، ربما نتطرّق إليها لاحقًا في الأكاديمية. ترجمة وبتصرّف للمقال Introduction to Object-Oriented JavaScript.1 نقطة