ما هو النوع؟ ببساطة، النوع هو تعيين معنى معين لتسلسل ثنائي في الذاكرة. على سبيل المثال، التسلسل الثنائي 0100 0000 0111 0000 0001 0101 0100 1011 1100 0110 1010 0111 1110 1111 1001 1110 هو 4643234631018606494 إذا تم عرضه كنوع صحيح غير موقّع بحجم 64 بت 54 قاعدة للتمثيل الثنائي لأرقام الفاصلة العائمة (انظر الملحق 1) مزدوجة الدقة نوع النقطة العائمة هو 257.331.
تستخدم معظم لغات الكمبيوتر المتغيرات لتخزين البيانات وتمثيلها. تحدد بعض اللغات نوعًا للمتغيرات، ولا يمكن تغيير هذا النوع خلال البرنامج (سواء في وقت الترجمة أو وقت التشغيل). في المقابل، يمكن للمتغيرات في JavaScript وبعض اللغات الأخرى تخزين أي نوع، وتستخدم متغيرات غير مكتوبة. ما إذا كان نوع المتغير موجودًا لا علاقة له بالبناء، على سبيل المثال، يوفر C# أيضًا متغيرات من النوع var، ومع ذلك، ستتسبب العبارة التالية في حدوث خطأ في C#:
فار أ=1;
أ = "سلسلة"؛
والسبب هو أن الكلمة الأساسية var الخاصة بـ C# تتجاهل فقط تعريف نوع المتغير، وتستنتج تلقائيًا نوع المتغير بناءً على تعبير التهيئة، لذلك لا يزال متغير var الخاص بـ C# يحتوي على نوع. في JavaScript، يمكنك تعيين أي قيمة لمتغير معين في أي وقت، لذلك لا يتم كتابة متغيرات JavaScript.
وفقًا لطريقة تصميم نظام كتابة لغة الكمبيوتر، يمكن تقسيمها إلى نوعين: النوع القوي والنوع الضعيف. يكمن الاختلاف بين الاثنين في ما إذا كان التحويل الضمني بين الأنواع المختلفة يمكن أن يكون شفافًا للمستخدم أثناء الحساب. من وجهة نظر المستخدم، إذا كانت اللغة يمكنها تحويل جميع أنواعها ضمنيًا، فعندما تشارك متغيراتها وتعبيراتها وما إلى ذلك في العمليات، حتى لو كان النوع غير صحيح، فلا يزال بإمكانها الحصول على النوع الصحيح من خلال التحويل الضمني للمستخدم يبدو الأمر كما لو أن جميع الأنواع يمكنها تنفيذ جميع العمليات، لذلك تسمى هذه اللغة ضعيفة الكتابة. في المقابل، قد لا يكون هناك بالضرورة تحويلات ضمنية بين الأنواع في لغة مكتوبة بقوة (على سبيل المثال، C++ هي لغة مكتوبة بقوة، ولكن يمكن تحويل double وint إلى بعضهما البعض في C++، ولكن التحويل مطلوب بين double وany). نوع المؤشر ).
يمكن للأنواع أن تساعد المبرمجين على كتابة البرامج الصحيحة، وتعمل كقيود في العملية الفعلية لكتابة البرامج. القاعدة العامة هي أنه كلما كان القيد أقوى، كان أقل عرضة للخطأ، ولكن كلما زادت صعوبة كتابة البرنامج. اللغات المكتوبة بقوة والتي تحتوي على متغيرات لها أنواع لها أقوى القيود، والممثل النموذجي هو C++، اللغات المكتوبة بشكل ضعيف والتي تحتوي على متغيرات غير مكتوبة لديها أضعف القيود، مع كون JavaScript هو الممثل النموذجي. في JavaScript، نظرًا لأن القيود ضعيفة نسبيًا، فمن المحتمل حدوث هذا الخطأ:
فار أ =200؛
فار ب = "1"؛
فار ج= أ + ب;
قد تتوقع أن يكون c هو 201، ولكنه في الواقع "2001"، وهو خطأ لا يحدث أبدًا في اللغات المكتوبة بقوة. ومع ذلك، نظرًا لأن JavaScript لا تحتوي على هذه القيود، فيمكنها بسهولة ربط الأنواع الرقمية وأنواع السلاسل. ولذلك، فإن القيود والمرونة هي دائمًا مجموعة من الميزات التي يجب أن تكون متوازنة لمصممي اللغة.
النوع هو قيد يعمل من خلال التحقق من النوع. في لغات مختلفة، يعمل فحص الكتابة في مراحل مختلفة، والتي يمكن تقسيمها إلى فحص وقت الترجمة وفحص وقت التشغيل. بالنسبة للغات المفسرة مثل جافا سكريبت، هناك مراحل مشابهة لعملية التجميع، وهي التحليل المعجمي وتحليل بناء الجملة. إذا تم الانتهاء من التحقق من نوع اللغات المفسرة أثناء تحليل بناء الجملة أو المرحلة السابقة، فيمكن أخذها في الاعتبار أيضًا على غرار التحقق من وقت الترجمة. لذا فإن العبارة الأكثر منطقية هي التحقق من النوع الثابت والتحقق من النوع الديناميكي.
ومن المثير للاهتمام أنه على الرغم من أن العديد من اللغات تتحقق من الأنواع في وقت الترجمة، إلا أنه لا يزال من الممكن الحصول على معلومات النوع الخاصة بها في وقت التشغيل. على سبيل المثال، يستخدم C# البيانات الوصفية لحفظ معلومات النوع أثناء وقت التشغيل، ويمكن للمستخدمين الحصول على الأنواع واستخدامها من خلال معلومات الانعكاس.
تعطي جافا سكريبت الأولوية للمرونة في كل جانب من جوانب تصميمها، لذا فهي تستخدم التحقق الديناميكي من النوع ولا تتحقق من الأنواع بشكل فعال إلا عند إجراء عدد قليل جدًا من العمليات المحددة. يمكنك الحصول على معلومات النوع لأي متغير أو تعبير في وقت التشغيل والتحقق من صحته من خلال منطق البرنامج.
هناك 9 أنواع محددة في معيار JavaScript: غير محدد Null Boolean String Number Object Reference List Completion
من بينها، يتم استخدام الأنواع الثلاثة لاستكمال القائمة المرجعية فقط أثناء وقت تشغيل تحليل اللغة ولا يمكن الوصول إليها مباشرة من البرنامج ولن يتم تقديمها هنا. وفيما يلي يمكننا التعرف على هذه الأنواع الستة:
يحتوي النوع غير المحدد على قيمة واحدة فقط، غير محددة، وهي القيمة عندما لا يتم تعيين قيمة للمتغير. في JS، يحتوي الكائن العام على خاصية غير محددة تمثل غير محددة قم بتعيين قيمة للخاصية العامة غير المحددة لتغيير قيمتها.
يحتوي النوع Null أيضًا على قيمة واحدة فقط، وهي null، لكن JavaScript تزوده بكلمة أساسية null لتمثيل هذه القيمة الفريدة. دلالات النوع Null هي "مرجع كائن فارغ".
لدى Boolean قيمتان: صحيح وخطأ
التفسير الرسمي لنوع السلسلة هو سلسلة من أنواع الأعداد الصحيحة غير الموقعة ذات 16 بت، والتي تُستخدم فعليًا لتمثيل المعلومات النصية المشفرة في UTF-16.
يحتوي رقم JavaScript على إجمالي 18437736874454810627 (أي 264-253 +3). يتم تخزين رقم JavaScript بنوع النقطة العائمة مزدوجة الدقة، باستثناء أن 9007199254740990 يمثل NaN، والذي يتوافق مع IEEE 754 (انظر الملحق 1) ويشغل 64 بت و8 بايت.
النوع الأكثر تعقيدًا في JavaScript هو الكائن، وهو عبارة عن مجموعة غير مرتبة من سلسلة من الخصائص. الوظيفة هي كائن ينفذ الخاصية الخاصة [[استدعاء]]. يمكن لمضيف JavaScript أيضًا توفير بعض الكائنات الخاصة.
لقد تحدثت عن الأنواع المحددة في معيار JS من قبل، ومع ذلك، هناك مشكلة لا يمكن تجاهلها وهي أن معيار JS مكتوب لمنفذي JS، وليس من الضروري تحديد الأنواع وفقًا للمعيار نظرًا لأن JS يتم تحويل الأنواع غير الكائنية تلقائيًا إلى كائنات مقابلة عند تنفيذ عملية، لذا فإن "str". length يعادل في الواقع طول (new String("str") ليست فكرة سيئة أن يكون كلاهما من نفس النوع. نحن نستخدم بعض ميزات اللغة في JS لإجراء التمييز بين أنواع وقت التشغيل، لكن نتائج هذه الطرق مختلفة، عليك أن تقرر أيهما أفضل أو أسوأ.
Typeof هو عامل تشغيل في لغة JS، ومن الواضح أنه يستخدم للحصول على النوع وفقًا لمعيار JavaScript، ويحصل على تمثيل السلسلة لاسم النوع المتغير. منطقي، رقم، غير محدد، كائن، وظيفة، ومعيار جافا سكريبت يسمح لمنفذيه بتخصيص قيمة نوع بعض الكائنات.
توجد قائمة الوصف هذه في معيار JS:
يكتب | نتيجة |
غير محدد | "غير محدد" |
باطل | "هدف" |
منطقية | "منطقي" |
رقم | "رقم" |
خيط | "خيط" |
الكائن (أصلي ولا ينفذ [[استدعاء]]) | "هدف" |
كائن (أصلي وتنفيذي [[استدعاء]]) | "وظيفة" |
كائن (مضيف) | تعتمد على التنفيذ |
المثال التالي يأتي من Rimifon of 51js، والذي يوضح الحالة التي تنتج فيها نتيجة typeof في IE "تاريخ" و"غير معروف":
var xml=document.createElement("xml");
var rs=xml.recordset;
rs.Fields.Append("date", 7, 1);
rs.Fields.Append("bin", 205, 1);
rs.Open();
rs.AddNew();
rs.Fields.Item("تاريخ").Value = 0;
rs.Fields.Item("bin").Value = 21704;
rs.Update();
تاريخ فار = rs.Fields.Item("تاريخ").Value;
فار بن = rs.Fields.Item("bin").Value;
rs.Close();
تنبيه (تاريخ)؛
تنبيه (بن)؛
تنبيه([نوع التاريخ، نوع الصندوق]);
حاول{alert(date.getDate())}catch(err){alert(err.message)}
هناك في الواقع العديد من الانتقادات حول طريقة الحكم هذه الأقرب إلى دلالات "الكتابة". أحدها هو أنه لا يمكن التمييز بين الكائنات المختلفة في برمجة JS، غالبًا ما يتم استخدام عدد كبير من الكائنات المختلفة، ويمكن لـ typeof فقط إعطاء نتيجة غامضة "كائن" لجميع الكائنات، مما يقلل بشكل كبير من التطبيق العملي لها.
يُترجم معنى المثيل إلى اللغة الصينية على أنه "مثال لـ...". ومن المفهوم حرفيًا، أنه مصطلح يعتمد على البرمجة الشيئية القائمة على الفصل، ولا تقدم JS فعليًا الدعم للبرمجة القائمة على الفصل في مستوى اللغة. على الرغم من أن معيار JavaScript لا يذكر كلمة واحدة، إلا أن تصميم بعض الكائنات المضمنة وإعدادات المشغل كلها تشير إلى طريقة "رسمية" لتنفيذ الفئات، أي من استخدام الوظائف كفئات، عندما يتصرف المشغل الجديد في الوظيفة، يتم تعيين سمة النموذج الأولي للوظيفة على النموذج الأولي للكائن المنشأ حديثًا، ويتم استخدام الوظيفة نفسها كمنشئ.
ولذلك، فإن الكائنات التي تم إنشاؤها من العملية الجديدة لنفس الوظيفة تعتبر مثيلات لفئة. ما تشترك فيه هذه الكائنات هو: 1. لها نفس النموذج الأولي و2. تتم معالجتها بواسطة نفس المُنشئ. وinstanceof هو عامل يتحقق "ما إذا كان المثيل ينتمي إلى فئة ما" بالتزامن مع طريقة تنفيذ الفئة هذه. يمكنك أيضًا تخمين أنه من الصعب جدًا التحقق مما إذا كان الكائن قد تمت معالجته بواسطة المُنشئ، ولكن من الأسهل بكثير التحقق من النموذج الأولي الخاص به، لذلك يتم فهم تنفيذ المثيل من منظور النموذج الأولي تحقق من أن السمة [ [النموذج الأولي]] متوافقة مع النموذج الأولي لوظيفة معينة. لاحظ أن [[prototype]] هنا ملكية خاصة، ويمكن الوصول إليها باستخدام __proto__ في SpiderMonkey (وهو محرك Firefox's JS).
النموذج الأولي له معنى فقط لنوع الكائن الموصوف بواسطة المعيار، لذلك سيصبح مثيل المثيل خطأ لجميع الكائنات غير الكائن، ويمكن لمثيل المثيل فقط تحديد ما إذا كان ينتمي إلى نوع معين، ولكن لا يمكنه الحصول على النوع من الواضح أيضًا أنه يمكن أن يميز نفسه عن كائن تم إنشاؤه من "فئة" محددة.
في الواقع، يمكن خداع المثيل على الرغم من أنه لا يمكن تغيير السمة الخاصة [[النموذج الأولي]] للكائن الذي يستخدمه، إلا أن النموذج الأولي للوظيفة هو سمة عامة. يوضح التعليمة البرمجية التالية كيفية خداع المثيل.
وظيفة كلاسا () {}؛
دالة ClassB(){};
var o = new ClassA();// إنشاء كائن من الفئة A
ClassB.prototype = ClassA.prototype;
تنبيه (o مثيل ClassB)// نجح الخداع الحقيقي - -!
من الصعب في الأصل استدعاء Object.prototype.toString. تغطي جميع فئات JavaScript المضمنة طريقة toString بالنسبة للكائنات التي تم إنشاؤها بواسطة فئات غير مضمنة، يمكن لـ Object.prototype.toString الحصول على هذا النوع من [object Object] فقط. نتيجة. لذلك، لفترة طويلة، لم يتم اكتشاف التأثير السحري لهذه الوظيفة.
في المعيار، وصف Object.prototype.toString هو 3 جمل فقط
1. احصل على سمة [[الفئة]] لهذا الكائن
2. احسب سلسلة عن طريق وصل السلاسل الثلاث "[object "، والنتيجة(1)، و "]"
3. إرجاع النتيجة (2).
من الواضح أن Object.prototype.toString يحصل في الواقع على سمة [[class]] للكائن، لكنني لا أعرف ما إذا كان ذلك مقصودًا أم لا. سيتم استخدام جميع كائنات الوظائف المضمنة في JS String Number Array RegExp... عند استخدام جديد لإنشاء كائنات، قم بتعيين سمة [[class]] بحيث يمكن استخدام سمة [[class]] كأساس جيد للحكم على النوع.
نظرًا لأن Object.prototype.toString يأخذ خاصية هذا الكائن، يمكنك تحديد هذا الكائن ثم الحصول على النوع باستخدام Object.prototype.toString.call أو Object.prototype.toString.apply.
على الرغم من أن Object.prototype.toString ذكي، إلا أنه لا يمكنه الحصول على نوع الكائن الذي تم إنشاؤه بواسطة الوظيفة المخصصة، لأن الوظيفة المخصصة لا تقوم بتعيين [[الفئة]]، ولا يمكن الوصول إلى هذه الخاصية الخاصة في البرنامج. أكبر ميزة لـ Object.prototype.toString هي أنه يمكن أن يجعل 1 والرقم الجديد (1) من نفس نوع الكائن. في معظم الأحيان، يتم استخدام الاثنين بنفس الطريقة.
ومع ذلك، تجدر الإشارة إلى أنه عندما تشارك قيمة منطقية جديدة (خطأ) في عمليات منطقية، فإن النتيجة تكون عكس الخطأ تمامًا. إذا تم اعتبار الاثنين من نفس النوع في هذا الوقت، فسيؤدي ذلك بسهولة إلى أخطاء يصعب ارتكابها يفحص.
من أجل مقارنة الأنواع الثلاثة المذكورة أعلاه من أساليب الحكم، قمت بإعداد جدول حتى يتمكن الجميع من إجراء مقارنة شاملة بين عدة طرق. ولتسهيل المقارنة قمت بتوحيد النتائج التي تم الحصول عليها من خلال عدة طرق للحكم:
هدف | typeof | مثيل | Object.prototype.toString | معيار |
"اي بي سي" | خيط | —— | خيط | خيط |
سلسلة جديدة ("اي بي سي") | هدف | خيط | خيط | هدف |
وظيفة مرحبا (){} | وظيفة | وظيفة | وظيفة | هدف |
123 | رقم | —— | رقم | رقم |
الرقم الجديد(123) | هدف | رقم | رقم | هدف |
صفيف جديد (1،2،3) | هدف | صفيف | صفيف | هدف |
نيوماي تايب () | هدف | نوعي | هدف | هدف |
باطل | هدف | —— | هدف | باطل |
غير محدد | غير محدد | —— | هدف | غير محدد |
في الواقع، من الصعب تحديد أي من الطرق المذكورة أعلاه أكثر منطقية. حتى الأحكام الواردة في المعيار تعكس فقط آلية تشغيل JS بدلاً من أفضل ممارسات الاستخدام. رأيي الشخصي هو التقليل من أهمية مفهوم "النوع" والتركيز أكثر على قيود "كيف أريد استخدام هذا الكائن". يمكن أن يؤدي استخدام typeof وinstanceof للتحقق إلى نفس التأثير الذي تحققه اللغة المكتوبة بقوة عند الحاجة.
بت الإشارة: يستخدم لتمثيل الإشارات الإيجابية والسلبية
الأس: يستخدم لتمثيل أرقام القوة
العشري (العشري): يستخدم للإشارة إلى الدقة