فهم واستخدام عامل التشغيل typeof في JavaScript: دليلك الشامل لفحص أنواع البيانات
تعتبر أنواع البيانات وفحصها جوانب أساسية في أي لغة برمجة. بينما تتميز العديد من لغات البرمجة مثل Java بالتحقق الصارم من الأنواع، مما يعني أن المتغير المعرّف بنوع معين لا يمكن أن يحتوي إلا على قيمة من هذا النوع، فإن JavaScript لغة ذات أنواع مرنة (أو ديناميكية). هذا يعني أن المتغير يمكن أن يحتوي على قيمة من أي نوع. يمكن تنفيذ كود JavaScript على النحو التالي:
let one = 1 ;
one = 'one' ;
one = true ;
one = Boolean ( true );
one = String ( 'It is possible' );
مع وضع ذلك في الاعتبار، من الأهمية بمكان معرفة نوع المتغير في أي وقت. يتم تحديد نوع المتغير من خلال نوع القيمة المعينة له. تمتلك JavaScript عامل تشغيل خاصًا يُسمى typeof يتيح لك الحصول على نوع أي قيمة. في هذا المقال، سنتعلم كيفية استخدام typeof، بالإضافة إلى بعض النقاط الهامة التي يجب الانتباه إليها.
أنواع البيانات في JavaScript
دعنا نلقي نظرة سريعة على أنواع البيانات في JavaScript قبل أن نتعمق في عامل التشغيل typeof. في JavaScript، هناك سبعة أنواع بدائية (primitive types). البدائي هو أي شيء ليس كائنًا (object). وهي:
StringNumberBigIntSymbolBooleanundefinednull
كل شيء آخر هو object – بما في ذلك array و function. الكائن هو مجموعة من أزواج المفاتيح والقيم (key-value pairs).
عامل التشغيل typeof في JavaScript
يأخذ عامل التشغيل typeof مُعاملاً واحدًا فقط (unary operator). يقوم بتقييم نوع المُعامل ويعيد النتيجة كسلسلة نصية (string). إليك كيفية استخدامه عند تقييم نوع رقم، مثل 007:
typeof 007 ; // returns 'number'
هناك صيغة بديلة لعامل التشغيل typeof حيث يمكنك استخدامه كـ function:
typeof (operand)
هذه الصيغة مفيدة عندما تريد تقييم تعبير (expression) بدلاً من قيمة واحدة. إليك مثال على ذلك:
typeof ( typeof 007 ); // returns 'string'
في المثال أعلاه، يتم تقييم التعبير typeof 007 إلى النوع number ويعيد السلسلة النصية 'number'. ثم ينتج عن typeof('number') القيمة 'string'. دعنا نلقي نظرة على مثال آخر لفهم أهمية الأقواس مع عامل التشغيل typeof.
typeof ( 999 -3223 ); // returns, "number"
إذا حذفت الأقواس، فستكون النتيجة NaN (ليس رقمًا – Not a Number):
typeof 999 -3223 ; // returns, NaN
هذا لأن typeof 999 سينتج عنه أولاً سلسلة نصية "number". التعبير "number" - 32223 ينتج عنه NaN، كما يحدث عند إجراء عملية طرح بين سلسلة نصية ورقم.
أمثلة عملية على عامل التشغيل typeof في JavaScript
يوضح مقتطف الكود التالي نتيجة فحص النوع لقيم مختلفة باستخدام عامل التشغيل typeof:
typeof 0 ; //'number'
typeof + 0 ; //'number'
typeof -0 ; //'number'
typeof Math .sqrt( 2 ); //'number'
typeof Infinity ; //'number'
typeof NaN ; //'number', even if it is Not a Number
typeof Number ( '100' ); //'number', After successfully coerced to number
typeof Number ( 'freeCodeCamp' ); //'number', despite it can not be coerced to a number
typeof true ; //'boolean'
typeof false ; //'boolean'
typeof Boolean ( 0 ); //'boolean'
typeof 12n ; //'bigint'
typeof '' ; //'string'
typeof 'freeCodeCamp' ; //'string'
typeof `freeCodeCamp is awesome` ; //'string'
typeof '100' ; //'string'
typeof String ( 100 ); //'string'
typeof Symbol (); //'symbol'
typeof Symbol ( 'freeCodeCamp' ); //'symbol'
typeof { blog : 'freeCodeCamp' , author : 'Tapas A' }; //'object';
typeof [ 'This' , 'is' , 101 ]; //'object'
typeof new Date (); //'object'
typeof Array ( 4 ); //'object'
typeof new Boolean ( true ); //'object';
typeof new Number ( 101 ); //'object';
typeof new String ( 'freeCodeCamp' ); //'object';
typeof new Object ; //'object'
typeof alert; //'function'
typeof function ( ) {}; //'function'
typeof ( () => {}); //'function' - an arrow function so, parenthesis is required
typeof Math .sqrt; //'function'
let a;
typeof a; //'undefined'
typeof b; //'undefined'
typeof undefined ; //'undefined'
typeof null ; //'object'
يوضح الجدول أدناه قيم فحص النوع التي يعيدها typeof:
| النوع (TYPE) | القيمة المعادة من typeof (RETURN VALUE) |
|---|---|
String |
'string' |
Number |
'number' |
BigInt |
'bigint' |
Symbol |
'symbol' |
Boolean |
'boolean' |
undefined |
'undefined' |
Function object |
'function' |
null |
'object' |
أي كائنات أخرى (Any other objects) |
'object' |
مغالطات شائعة عند استخدام عامل التشغيل typeof
هناك حالات قد لا يعيد فيها عامل التشغيل typeof الأنواع التي تتوقعها، مما قد يسبب ارتباكًا وأخطاءً. إليك بعض هذه الحالات:
نوع NaN هو رقم
typeof NaN ; //'number', even if it is Not a Number
نوع NaN هو 'number'. هذا غريب، حيث لا ينبغي لنا الكشف عن NaN باستخدام typeof. هناك طرق أفضل للتعامل مع ذلك، وسنراها بعد قليل.
نوع null هو كائن
typeof null ; //'object'
في JavaScript، يعتبر typeof null كائنًا، مما يعطي انطباعًا خاطئًا بأن null هو كائن، بينما هو في الواقع قيمة بدائية (primitive value). هذه النتيجة لـ typeof null هي في الواقع خطأ (bug) في اللغة. كانت هناك محاولة لإصلاحه في الماضي ولكن تم رفضها بسبب مشكلة التوافق مع الإصدارات السابقة (backward compatibility).
نوع المتغير غير المعلن هو undefined
قبل ES6، كان فحص نوع متغير غير معلن ينتج عنه 'undefined'. لكن هذه ليست طريقة آمنة للتعامل معها. مع ES6، يمكننا الإعلان عن متغيرات محددة النطاق (block-scoped variables) باستخدام الكلمتين المفتاحيتين let أو const. إذا استخدمتها مع عامل التشغيل typeof قبل تهيئتها، فستطرح خطأ ReferenceError.
typeof cat; // ReferenceError
let cat = 'brownie' ;
لاحظ أن هذا السلوك يحدث فقط إذا كان المتغير معلنًا باستخدام let أو const ولكنه لم يُهيأ بعد. أما إذا لم يتم الإعلان عن المتغير على الإطلاق، فسيظل typeof يعيد 'undefined' لتجنب ReferenceError في هذه الحالة.
نوع دالة المُنشئ (Constructor Function) هو كائن
جميع دوال المُنشئ (constructor functions)، باستثناء مُنشئ Function نفسه، ستكون دائمًا typeof 'object'.
typeof new String ( 'freeCodeCamp' ); //'object'
قد يؤدي هذا إلى بعض الارتباك، حيث نتوقع أن يكون النوع الفعلي (في المثال أعلاه، نوع string).
نوع المصفوفة (Array) هو كائن
على الرغم من صحة ذلك من الناحية الفنية، إلا أن هذا قد يكون الأكثر إحباطًا. نريد التمييز بين المصفوفة والكائن حتى لو كانت المصفوفة تقنيًا كائنًا في JavaScript.
typeof Array ( 4 ); //'object'
لحسن الحظ، هناك طرق للكشف عن المصفوفة بشكل صحيح. سنرى ذلك قريبًا.
ما بعد typeof: طرق أفضل لفحص الأنواع في JavaScript
الآن بعد أن رأينا بعض القيود على عامل التشغيل typeof، دعنا نرى كيفية إصلاحها وإجراء فحص أفضل للأنواع.
كيفية الكشف عن NaN
في JavaScript، NaN هي قيمة خاصة. تمثل قيمة NaN نتيجة تعبير حسابي لا يمكن تمثيله بالفعل. على سبيل المثال:
let result = 0 / 0 ;
console .log(result); // returns, NaN
أيضًا، إذا أجرينا أي عمليات حسابية مع NaN، فستكون النتيجة دائمًا NaN.
console .log( NaN + 3 ); // returns, NaN
لا يساعد فحص النوع على NaN باستخدام عامل التشغيل typeof كثيرًا لأنه يعيد النوع كـ 'number'. تمتلك JavaScript دالة عامة تُسمى isNaN() للكشف عما إذا كانت النتيجة NaN.
isNaN ( 0 / 0 ); // returns, true
ولكن هناك مشكلة هنا أيضًا:
isNaN ( undefined ); // returns true for 'undefined'
في ES6، تمت إضافة الدالة isNaN() إلى الكائن العام Number. هذه الدالة أكثر موثوقية وبالتالي فهي المفضلة.
Number .isNaN( 0 / 0 ); // returns, true
Number .isNaN( undefined ); // returns, false
جانب آخر مثير للاهتمام في NaN هو أنها قيمة JavaScript الوحيدة التي لا تساوي أبدًا أي قيم أخرى بما في ذلك نفسها. لذا، هذه طريقة أخرى للكشف عن NaN للبيئات التي لا تدعم ES6:
function isNaN ( input ) {
return input !== input;
}
كيفية الكشف عن null في JavaScript
لقد رأينا أن الكشف عن null باستخدام عامل التشغيل typeof مربك. الطريقة المفضلة للتحقق مما إذا كان شيء ما null هي باستخدام عامل المساواة الصارمة (===).
function isNull ( input ) {
return input === null ;
}
تأكد من عدم استخدام عامل التشغيل == عن طريق الخطأ. سيؤدي استخدام == بدلاً من === إلى اكتشاف نوع مضلل.
كيفية الكشف عن المصفوفة (Array) في JavaScript
منذ ES6 فصاعدًا، يمكننا الكشف عن المصفوفة باستخدام الدالة Array.isArray.
Array .isArray([]); // returns true
Array .isArray({}); // returns false
قبل ES6، كان بإمكاننا استخدام عامل التشغيل instanceof لتحديد المصفوفة:
function isArray ( input ) {
return input instanceof Array ;
}
حل عام لفحص الأنواع في JavaScript
هناك طريقة يمكننا من خلالها إنشاء حل عام لفحص الأنواع. ألقِ نظرة على الدالة Object.prototype.toString. هذه الدالة قوية جدًا ومفيدة للغاية لكتابة دالة مساعدة (utility method) لفحص الأنواع. عندما يتم استدعاء Object.prototype.toString باستخدام call() أو apply()، فإنها تعيد نوع الكائن بالتنسيق: [object Type]. الجزء Type في القيمة المعادة هو النوع الفعلي. دعنا نرى كيف يعمل مع بعض الأمثلة:
// returns '[object Array]'
Object .prototype.toString.call([]);
// returns '[object Date]'
Object .prototype.toString.call( new Date ());
// returns '[object String]'
Object .prototype.toString.call( new String ( 'freeCodeCamp' ));
// returns '[object Boolean]'
Object .prototype.toString.call( new Boolean ( true ));
// returns '[object Null]'
Object .prototype.toString.call( null );
هذا يعني أنه إذا أخذنا السلسلة المعادة فقط واستخرجنا الجزء Type، فسنحصل على النوع الفعلي. إليك محاولة للقيام بذلك:
function typeCheck ( value ) {
const return_value = Object .prototype.toString.call(value);
// we can also use regex to do this...
const type = return_value.substring( return_value.indexOf( " " ) + 1 , return_value.indexOf( "]" ));
return type.toLowerCase();
}
الآن، يمكننا استخدام الدالة typeCheck للكشف عن الأنواع:
typeCheck([]); // 'array'
typeCheck( new Date ()); // 'date'
typeCheck( new String ( 'freeCodeCamp' )); // 'string'
typeCheck( new Boolean ( true )); // 'boolean'
typeCheck( null ); // 'null'
ملخص
لتلخيص ما تعلمناه في هذا المقال:
- فحص الأنواع في
JavaScriptليس صارمًا مثل لغات البرمجة الأخرى. - استخدم عامل التشغيل
typeofللكشف عن الأنواع. - هناك صيغتان لعامل التشغيل
typeof:typeof operandوtypeof(expression). - قد تكون نتيجة عامل التشغيل
typeofمضللة في بعض الأحيان. نحتاج إلى الاعتماد على طرق أخرى متاحة (مثلNumber.isNaN،Array.isArray، وما إلى ذلك) في تلك الحالات. - يمكننا استخدام
Object.prototype.toStringلإنشاء طريقة عامة للكشف عن الأنواع.
الخلاصة التقنية
يُعد فهم كيفية التعامل مع أنواع البيانات في JavaScript أمرًا حيويًا للمطورين، نظرًا لطبيعتها الديناميكية. بينما يوفر عامل التشغيل typeof نقطة بداية جيدة لفحص الأنواع البدائية، إلا أن قيوده مع null والكائنات المُنشأة والمصفوفات تتطلب استخدام أدوات أكثر دقة مثل Number.isNaN() و Array.isArray() وعامل المساواة الصارمة ===. إن الحل العام المستند إلى Object.prototype.toString.call() يمثل نهجًا قويًا وموثوقًا لتحديد الأنواع بدقة عبر مختلف السيناريوهات، مما يعزز من قوة الكود وقابليته للصيانة في تطبيقات JavaScript المعقدة. يجب على المطورين دائمًا اختيار الأداة المناسبة للمهمة لضمان دقة فحص الأنواع وتجنب الأخطاء المحتملة.