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

تتيح لنا JavaScript التعامل مع أنواع البيانات الأولية (النصوص، الأرقام، وغيرها) كما لو أنها كائنات، كما تزودنا بتوابع (methods) لاستدعائها كما الكائنات. وسندرس هذه التوابع قريبًا، لكن لنرى أولًا كيف تعمل لأن الأنواع الأولية (primitives) ليست كائنات (أي object) وسنجعل الأمر واضحًا هنا.

لنرى إلى الفروق الأساسية بين الأنواع الأولية والكائنات.

النوع الأولي:

  • هو قيمة من نوع أولي (primitive type).
  • يوجد 6 أنواع أولية: نص string، رقم number، قيمة منطقية boolean، رمز symbol، قيمة فارغة null ، وقيمة غير معرفة undefined.

الكائن:

  • قادر على تخزين العديد من القيم ضمن خاصيات.
  • يمكن إنشاؤه باستخدام {}، مثلًا: {name: "John", age: 30}. يوجد أنواع أخرى من الكائنات في JavaScript: مثلا، تعد الدوال كائنات.

أحد أفضل الأشياء بالنسبة للكائنات هو إمكانية تخزين دالة في خاصية من خواص هذا الكائن.

let john = {
  name: "John",
  sayHi: function() {
    alert("Hi buddy!");
  }
};

john.sayHi(); // Hi buddy!

إذًا، أنشأنا الكائن john محتويًا الدالة sayHi.

يوجد العديد من الكائنات المدمجة في اللغة، مثل التي تتعامل مع التواريخ، الأخطاء، عناصر HTML، وغيرها. ولديها خاصيات وتوابع مختلفة. لكن لهذه الميزات ثمن!

الكائنات أثقل من المتغيرات الأولية، فهي تتطلب موارد (resources) أكثر لدعم آليتها الداخلية.

نوع أولي مثل كائن

هنا نجد التناقض الذي واجهه مُنشِئ JavaScript:

  • يوجد الكثير من الأشياء التي قد يريد أحد القيام بها مع المتغيرات الأولية مثل النص أو الرقم. سيكون من الرائع الوصول إليها كتوابع.
  • يجب أن تكون المتغيرات الأولية سريعة وخفيفة قدر الامكان.

يبدو الحل صعبًا قليلًا، لكن هذا هو:

  1. تبقى المتغيرات الأولية كما هي، قيمة واحدة مثل المطلوب.
  2. تتيح لنا اللغة الوصول إلى توابع وخاصيات النصوص، الأرقام، القيم المنطقية، والرموز.
  3. حتى يعمل ذلك، يُنشَأ «كائن مغلِّف» (object wrapper) خاص يزود المتغيرات بالوظائف الإضافية، ثم يُدَمَّر.

يختلف الكائن المغلِّف "object wrappers" من نوع أولي لآخر ويُسمَى: String، و Number، و Boolean، و Symbol، لذا فإنه يزود كل نوع بمجموعة مختلفة من التوابع الخاصة به.

مثلا، يوجد دالة للنصوص str.toUpperCase() والتي تُرجِع النص str بأحرف كبيرة.

آلية عملها:

let str = "Hello";

alert( str.toUpperCase() ); // HELLO

الأمر بسيط، أليس كذلك؟ ما يحدث فعلا في الدالة str.toUpperCase()‎ هو كالتالي:

1- النص str هو متغير أولي، لذا فعند محاولة الوصول إلى خاصيتِه، يُنشَأ كائن خاص يعرف قيمة النص ويحتوي هذا الكائن على توابع مفيدة من بينها التابع toUpperCase()‎.

2- تعمل هذه الدالة وتُرجِع نصًا جديدًا (يمكن عرضه باستخدام alert).

3- يُدَمَّر الكائن الخاص تاركًا المتغير الأولي str.

هكذا يمكن للمتغيرات الأولية أن تحوي توابعًا، وتبقى خفيفة في الوقت ذاته. يُحَسِّن محرك JavaScript هذه العملية بدرجة عالية. قد يتخطى إنشاء الكائن الإضافي، لكن يجب أن يظل قائمًا بالعمل المطلوب كما لو كان قد أنشأ الكائن.

لدى الأعداد توابع خاصة بها، مثلا، toFixed(n) تُقرِّب الرقم المُعطَى إلى الدقة المطلوبة:

let n = 1.23456;

alert( n.toFixed(2) ); // 1.23

سنرى المزيد من التوابع المخصصة في فصل النصوص والأعداد.

البانيات String أو Number أو Boolean هي للاستخدام الداخلي فقط

تتيح لنا بعض اللغات مثل Java إنشاء كائنات مغلِّفة "wrapper objects" بشكل صريح باستخدام صيغة مثل: new Number(1)‎ أو new Boolean(false)‎. ذلك ممكن أيضًا في JavaScript لأسباب تاريخية، لكنه غير مستحسن لأن الأمور قد تسير بشكل خاطئ في العديد من الأماكن.

مثلا:

alert( typeof 0 ); // "number"

alert( typeof new Number(0) ); // "object"!

تكون قيمة الكائنات دائمًا true في if، لذا سيتم عرض ما بداخل alert أدناه:

let zero = new Number(0);

if (zero) { // 
  alert( "zero is truthy!?!" );
}

تقييم قيمة المتغير zero هنا هي القيمة المنطقية true، لأنه كائن.

بالمقابل، من الممكن استخدام التوابع String/Number/Boolean بدون new، إذ تقوم هذه التوابع بتحويل القيمة إلى النوع المقابل: إلى نص، أو رقم، أو قيمة منطقية (أولية).

مثال: الأمر التالي صحيح تمامًا:

let num = Number("123"); // تحوِّل النص إلى رقم

ليس لدى القيمتان الأوليتان null/undefined توابعًا

النوعان الأوليان null و undefined هما حالة استثناء، فليس لديها كائن مغلِّف (wrapper object) ولا توابع، إذ يعدان من الأنواع الأكثر أولية.

ستتسبب المحاولة في الوصول إلى خاصية بظهور خطأ:

alert(null.test); // error

الخلاصة

  • لدى الأنواع الأولية توابع مساعدة عدا null و undefined تسهل التعامل معها، سندرسها في الفصول اللاحقة.
  • تعمل هذه التوابع عبر كائنات مؤقتة، لكن محرك JavaScript مُعد لتحسين العملية داخليًا. لذا فإن استدعاء الكائن لا يتطلب الكثير من الموارد.

المهام

هل من الممكن إضافة خاصية نصية؟

الأهمية: 5

خذ بالحسبان الشيفرة التالية:

let str = "Hello";

str.test = 5;

alert(str.test);

ماذا تظن؟ هل ستعمل؟ هل ستُعرَض؟

الحل

جرب تشغيلها:

let str = "Hello";

str.test = 5; // (*)

alert(str.test);

يعتمد الأمر على إن كنت تستخدم use strict أم لا، قد تكون النتيجة أحد الخيارين:

1- undefined بدون استخدام الوضع الصارم 2- خطأ في الوضع الصارم

لماذا؟ لنفكر فيمَ يحصل في السطر (*):

1- يُنشئ "wrapper object" عند محاولة الوصول إلى خاصية للمتغير str.

2- الكتابة إلى هذه الخاصية يُعَدُّ خطأ في الوضع الصارم.

3- في الحالة الأخرى، تستمر عملية التخزين في الخاصية، يحصل الكائن على الخاصية test. لكن، يُدمَّر الكائن بعد ذلك فلا يصبح لدى str مرجِعًا إليه مما يجعل قيمتها غير معرفة.

يوضح هذا المثال أن المتغيرات الأولية ليست كائنات.

ترجمة -وبتصرف- للفصل Methods of primitives من كتاب The JavaScript Language

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...