في الواقع، يعد Typeof في JavaScript معقدًا للغاية، ويمكن استخدامه للقيام بأشياء كثيرة، ولكنه يحتوي أيضًا على العديد من السلوكيات الغريبة. تسرد هذه المقالة استخداماته المتعددة، وتشير أيضًا إلى المشكلات والحلول الموجودة.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FOperators%2Ftypeof
> نوع غير محدد
"غير محدد"
> typeof null // خطأ معروف
'هدف'
> نوع صحيح
"منطقي"
> النوع 123
'رقم'
> نوع "اي بي سي"
'خيط'
> نوع الوظيفة () {}
'وظيفة'
> النوع {}
'هدف'
>نوع[]
'هدف'
> نوع المتغير غير المعروف
"غير محدد"
1. تحقق مما إذا كان المتغير موجودًا وله قيمة.
سيُرجع الدالة typeof القيمة "غير محددة" في حالتين: عندما لا يتم التصريح عن المتغير، وعندما تكون قيمة المتغير غير محددة، على سبيل المثال:
> نوع المتغير غير المحدد === "غير محدد" صحيح > var المعلن متغير > نوع المتغير المعلن "غير محدد" > نوع غير محدد "غير محدد"
هناك طرق أخرى لاكتشاف ما إذا كانت القيمة غير محددة:
> قيمة فار = غير محددة؛ > القيمة === صحيحة غير محددة
ولكن إذا تم استخدام هذه الطريقة على متغير غير معلن، فسيتم طرح استثناء، لأن typeof فقط يمكنه اكتشاف المتغيرات غير المعلنة بشكل طبيعي دون الإبلاغ عن خطأ:
> undeclaredVariable === خطأ مرجعي غير محدد: لم يتم تعريف متغير غير معلن
ملاحظة: المتغيرات غير المهيأة، والمعلمات الرسمية التي لا تحتوي على معلمات تم تمريرها، والخصائص غير الموجودة لن تواجه المشكلات المذكورة أعلاه، لأنها يمكن الوصول إليها دائمًا والقيمة غير محددة دائمًا:
> var المعلن متغير > المعلن === صحيح غير محدد > (وظيفة (x) { return x === غير محدد }()) صحيح > ({}).foo === صحيح غير محدد
ملاحظة المترجم: لذلك، إذا كنت تريد اكتشاف وجود متغير عام قد لا يتم الإعلان عنه، فيمكنك أيضًا استخدام if(window.maybeUndeclaredVariable){}
المشكلة: typeof مرهق لإنجاز مثل هذه المهمة.
الحل: هذا النوع من العمليات ليس شائعًا جدًا، لذلك يشعر بعض الأشخاص أنه ليس هناك حاجة لإيجاد حل أفضل، ولكن ربما يقترح شخص ما عاملاً خاصًا:
> تعريف متغير غير معلن خطأ > تعريف متغير متغير > تعريف متغير خاطئ
أو ربما يحتاج المرء أيضًا إلى عامل يكتشف ما إذا كان قد تم الإعلان عن متغير:
> تم الإعلان عن متغير غير معلن خطأ > تم الإعلان عن متغير > تم الإعلان عن متغير صحيح
ملاحظة المترجم: في لغة Perl، العامل المحدد أعلاه يعادل المحدد()، والعامل المعلن أعلاه يعادل موجود().
2. تحديد ما إذا كانت القيمة لا تساوي غير محددة أو خالية.
المشكلة: إذا كنت تريد التحقق مما إذا كانت القيمة قد تم تعريفها (القيمة ليست غير محددة أو فارغة)، فستواجه أحد أشهر مراوغات typeof (تعتبر خطأ): تقوم typeof null بإرجاع "object":
> نوع "الكائن" الفارغ
ملاحظة المترجم: لا يمكن القول إلا أن هذا خطأ في تطبيق JavaScript الأصلي، وهذه هي الطريقة التي تم بها الآن توحيد المعيار V8 وتنفيذه typeof null === "null"، ولكنه أثبت في النهاية أنه غير ممكن. //wiki .ecmascript.org/doku.php?id=harmony:typeof_null
الحل: لا تستخدم typeof لهذه المهمة، استخدم وظيفة مثل هذه بدلاً من ذلك:
الوظيفة محددة (x) { return x !== null && x !== undef };
الاحتمال الآخر هو تقديم "عامل القيمة الافتراضية"، حيث يُرجع التعبير التالي القيمة الافتراضية إذا لم يتم تعريف myValue:
القيمة الافتراضية؟؟
التعبير أعلاه يعادل:
(myValue !== غير محدد && myValue !== null) ?
أو:
myValue ??= defaultValue
في الحقيقة، هذا تبسيط للجملة التالية:
myValue = myValue ؟؟
عند الوصول إلى خاصية متداخلة، مثل bar، قد تحتاج إلى مساعدة عامل التشغيل هذا:
obj.foo.bar
إذا كان obj أو obj.foo غير محدد، فسيطرح التعبير أعلاه استثناءً.؟؟ يسمح للتعبير أعلاه بإرجاع القيمة الأولى التي تمت مواجهتها عند اجتياز طبقة الخصائص بطبقة غير محددة أو فارغة:
obj.؟؟foo.??bar
التعبير أعلاه يعادل:
(obj === غير محدد || obj === null) ? obj : (obj.foo === غير محدد || obj.foo === null) ?
3. التمييز بين قيم الكائنات والقيم البدائية
تختبر الدالة التالية ما إذا كانت x قيمة كائن:
function isObject(x) { return (typeof x === "function" || (typeof x === "object" && x !== null)});
المشكلة: الاكتشاف أعلاه معقد لأن typeof يعتبر الوظائف والكائنات أنواعًا مختلفة، ويقوم typeof null بإرجاع "object".
الحل: يتم أيضًا استخدام الطريقة التالية غالبًا للكشف عن قيم الكائنات:
الوظيفة isObject2(x) { return x === Object(x));
تحذير: قد تعتقد أنه يمكنك استخدام مثيل الكائن للكشف هنا، لكن مثيل الكائن يحدد علاقة المثيل باستخدام النموذج الأولي للكائن، فماذا عن الكائنات التي لا تحتوي على نماذج أولية:
> var obj = Object.create(null > Object.getPrototypeOf(obj) null);
obj هو بالفعل كائن، لكنه ليس مثيلًا لأي قيمة:
> نوع الكائن 'كائن' > مثيل كائن كائن خطأ
من الناحية العملية، نادرًا ما تواجه مثل هذا الكائن، لكنه موجود وله استخداماته.
ملاحظة المترجم: Object.prototype هو كائن موجود بشكل افتراضي وليس له نموذج أولي.
>Object.getPrototypeOf(Object.prototype)null>نوع Object.prototype'object'>مثيل Object.prototype للكائن خطأ
4. ما هو نوع القيمة الأولية؟
typeof هي أفضل طريقة للتحقق من نوع القيمة البدائية.
> نوع "abc" 'سلسلة' > نوع غير محدد "غير محدد"
المشكلة: يجب أن تكون على دراية بالسلوك الغريب لـ typeof null.
> typeof null // كن حذرًا!
الحل: يمكن للوظيفة التالية حل هذه المشكلة (فقط لحالة الاستخدام هذه).
function getPrimitiveTypeName(x) { var typeName = typeof x; Switch(typeName) { الحالة "غير محددة": الحالة "المنطقية": الحالة "الرقم": الحالة "السلسلة": إرجاع typeName: if (x == = null) { return "null" } default: // لم يتم تمرير أي من الأحكام السابقة throw new TypeError("المعلمة ليست قيمة أولية:"+x } });
الحل الأفضل: تنفيذ دالة getTypeName()، والتي بالإضافة إلى إرجاع نوع القيمة الأصلية، يمكنها أيضًا إرجاع السمة الداخلية [[Class]] لقيمة الكائن، وإليك كيفية تنفيذ هذه الوظيفة (ملاحظة المترجم: jQuery $.type هو مثل هذا التنفيذ)
5. ما إذا كانت قيمة معينة دالة
يمكن استخدام typeof لاكتشاف ما إذا كانت القيمة دالة > typeof function () {} 'function' > typeof Object.prototype.toString 'function'.
من حيث المبدأ، على سبيل المثال يمكن للوظيفة أيضًا اكتشاف هذا المطلب للوهلة الأولى، يبدو أن طريقة الكتابة أكثر أناقة، ومع ذلك، فإن المتصفح لديه ميزة خاصة: كل إطار ونافذة له متغيرات عامة خاصة به إذا تم تمرير الكائن إلى إطار عمل آخر، فلن يعمل المثيل بشكل صحيح لأن الإطارين لهما مُنشئان مختلفان هذا هو سبب وجود طريقة Array.isArray() في ECMAScript 5. سيكون من الرائع أن تكون هناك طريقة عبر إطار عمل للتحقق مما إذا كان الكائن مثيلًا لمنشئ معين، إن getTypeName() أعلاه هو الحل البديل المتاح ، ولكن قد يكون هناك حل أكثر جوهرية.
6. نظرة عامة
ما يلي يجب أن يكون الميزات المطلوبة بشدة في JavaScript في الوقت الحالي، ويمكن أن يحل محل بعض الميزات الوظيفية لمسؤوليات typeof الحالية:
isDefined() (مثل Object.isDefined()): يمكن استخدامها كدالة أو عامل تشغيل
كائن ()
getTypeName()
آلية عبر إطار عمل لاكتشاف ما إذا كان الكائن عبارة عن مثيل لمنشئ محدد
إن الحاجة إلى التحقق مما إذا كان قد تم الإعلان عن متغير قد لا تتطلب عامل تشغيل خاصًا به.