البرمجة

عامل ?? في جافاسكربت

عامل الاستبدال اللاغي (Nullish Coalescing Operator) في JavaScript: تحليل شامل

مقدمة

يُعد عامل الاستبدال اللاغي (Nullish Coalescing Operator) من الميزات الحديثة التي أُضيفت إلى لغة JavaScript بدءًا من ECMAScript 2020 (ES11)، ويُشار إليه بالرمز ??. يمثل هذا العامل نقلة نوعية في كيفية التعامل مع القيم “اللاغية”، أي القيم التي تمثل الغياب الحقيقي للبيانات مثل null أو undefined.

في السابق، كانت طرق التعامل مع القيم الافتراضية غير دقيقة وتعتمد على عوامل منطقية قد تُنتج نتائج غير متوقعة، خصوصًا عندما تحتوي المتغيرات على قيم تعتبر “خاطئة” في المنطق Boolean ولكنها قيم صالحة في السياق البرمجي مثل الرقم 0 أو السلسلة الفارغة.

في هذا المقال، سيتم التعمق في شرح عامل الاستبدال اللاغي من حيث تعريفه، الفرق بينه وبين العوامل الأخرى المشابهة مثل ||، حالات الاستخدام، التفاصيل التقنية، التوافق مع المتصفحات، الفروقات الدقيقة، وتحليله من منظور البرمجة الدفاعية وأمان الكود.


تعريف عامل الاستبدال اللاغي ??

عامل الاستبدال اللاغي (Nullish Coalescing Operator) يُستخدم لتقديم قيمة افتراضية فقط إذا كانت القيمة الأصلية “null” أو “undefined”. أي أنه يتحقق مما إذا كانت القيمة مفقودة وليس فقط “falsy” كما يفعل العامل المنطقي OR (||).

البنية:

javascript
let result = a ?? b;

في هذا المثال:

  • إذا كانت a تساوي null أو undefined، فإن result ستكون b.

  • أما إذا كانت a تحتوي على أي قيمة أخرى — حتى لو كانت 0 أو سلسلة فارغة "" أو false — فإن result ستساوي a.


الفرق بين ?? و ||

في الماضي، كان المطورون يستخدمون العامل المنطقي OR (||) لتحديد قيم افتراضية، ولكن هذا كان يؤدي إلى مشكلات لأن || لا يميز بين القيم “المفقودة” (null/undefined) والقيم “الخاطئة” (falsy).

أمثلة توضيحية:

| التعبير | القيمة | باستخدام || | باستخدام ?? |
|———|——–|—————-|—————-|
| 0 | falsy | القيمة البديلة | 0 |
| false | falsy | القيمة البديلة | false |
| "" | falsy | القيمة البديلة | “” |
| null | nullish| القيمة البديلة | القيمة البديلة |
| undefined | nullish | القيمة البديلة | القيمة البديلة |

كود توضيحي:

javascript
let x = 0; let usingOr = x || 5; // 5 (لأن 0 قيمة falsy) let usingNullish = x ?? 5; // 0 (لأن 0 ليس null أو undefined)

حالات الاستخدام الشائعة

1. تعيين القيم الافتراضية دون تجاهل القيم الصفرية الصالحة

javascript
function greet(name) { let finalName = name ?? "ضيف"; console.log(`مرحبًا، ${finalName}`); }

2. التعامل مع المدخلات من النماذج (forms)

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

javascript
let ageInput = getInput("age"); // قد تكون 0 let age = ageInput ?? 18; // لا يتم استبدال 0 بالافتراضي

3. إعدادات التهيئة (Configuration Defaults)

عند دمج إعدادات المستخدم مع الإعدادات الافتراضية، يمكن استخدام ?? لتحديد القيم التي لم يحددها المستخدم.

javascript
const defaultConfig = { fontSize: 14, theme: "light" }; function getUserSettings(userConfig) { return { fontSize: userConfig.fontSize ?? defaultConfig.fontSize, theme: userConfig.theme ?? defaultConfig.theme }; }

الفروقات الدقيقة والتعامل مع الحواف البرمجية

لا يُعامل القيم false، 0، "" كقيم مفقودة

هذه النقطة أساسية جدًا: في كثير من تطبيقات JavaScript القديمة، كان يتم تجاهل هذه القيم باعتبارها “غير موجودة” باستخدام ||. هذا يؤدي إلى فقدان بعض البيانات. أما مع ??، يمكن الاحتفاظ بهذه القيم ومعالجتها بشكل سليم.

javascript
let count = 0; console.log(count || 5); // 5 console.log(count ?? 5); // 0

الحذر من الدمج مع || و &&

استخدام ?? مع || أو && في تعبير واحد يؤدي إلى خطأ في JavaScript إلا إذا تم استخدام الأقواس لتحديد الأولويات:

javascript
// خطأ let result = a || b ?? c; // SyntaxError // صحيح let result = (a || b) ?? c;

التوافق مع المتصفحات

عامل ?? مدعوم في معظم المتصفحات الحديثة مثل:

المتصفح الحد الأدنى للإصدار
Chrome 80
Firefox 72
Safari 13.1
Edge 80
Node.js 14

لضمان التوافق مع الإصدارات القديمة، يمكن استخدام أدوات تحويل الشيفرة (transpilers) مثل Babel التي تدعم تحويل هذا العامل إلى بناء متوافق أقدم.


استخدام ?? مع التقييم القصير (Short-Circuiting)

كما في || و &&، فإن ?? يعتمد على التقييم القصير، ما يعني أن الجزء الأيمن من التعبير لن يتم تقييمه إذا لم يكن هناك حاجة إليه.

javascript
function getDefault() { console.log("تم تنفيذ getDefault()"); return "افتراضي"; } let val = "متاح"; let result = val ?? getDefault(); // لن يتم تنفيذ getDefault()

مقارنة تفصيلية بين عوامل التقييم المختلفة في JavaScript

العامل يتحقق من يُرجع خاصية التقييم القصير
` ` falsy
&& falsy أول قيمة falsy أو الأخيرة نعم
?? nullish أول قيمة غير nullish أو الأخيرة نعم

إدماجه مع الأنماط البرمجية الحديثة

في React

jsx
function UserProfile({ name }) { return <h1>{name ?? "زائر مجهول"}h1>; }

في Vue.js

html
<span>{{ user.age ?? 'غير محدد' }}span>

في Node.js

javascript
const port = process.env.PORT ?? 3000; app.listen(port, () => { console.log(`App running on port ${port}`); });

قياس الأداء وتحسين الكفاءة

عند استخدام ?? بدلًا من ||، يمكن تقليل الكلفة الحسابية لتقييم تعبيرات غير ضرورية، خصوصًا عند استخدام دوال ثقيلة أو الوصول إلى بيانات بعيدة.

javascript
// مثال غير كفء باستخدام || let userAge = getUserAge() || 25; // getUserAge() ستُنفذ دائمًا حتى لو كانت 0 // مثال باستخدام ?? let userAge = getUserAge() ?? 25; // ستُنفذ فقط إذا كانت null أو undefined

حالة استخدام: نظام الترجمة في واجهة متعددة اللغات

عند محاولة عرض ترجمات نصوص واجهة بلغة معينة مع وجود احتمالية فقدان بعض الترجمات:

javascript
const messages = { en: { welcome: "Welcome" }, ar: { welcome: "أهلاً وسهلاً" } }; function getTranslation(lang, key) { return messages[lang]?.[key] ?? messages['en'][key] ?? key; }

جدول توضيحي لمقارنة الحالات المختلفة

التعبير القيمة المعادة باستخدام ?? التفسير
null ?? "افتراضي" “افتراضي” لأن null يُعد nullish
undefined ?? "افتراضي" “افتراضي” لأن undefined يُعد nullish
false ?? "افتراضي" false لأن false ليست null أو undefined
0 ?? "افتراضي" 0 لأن 0 ليست null أو undefined
"" ?? "افتراضي" “” لأن السلسلة الفارغة ليست null أو undefined

الممارسات المثالية

  1. استخدام ?? بدلًا من || في الحالات التي تتطلب التمييز بين القيم nullish والقيم الأخرى.

  2. الابتعاد عن استخدام ?? و || أو && في نفس العبارة دون أقواس.

  3. استخدامه في تهيئة الإعدادات، والحقول الاختيارية، وواجهات المستخدم.

  4. ضمان التوافق عبر أدوات تحويل الشيفرة مثل Babel أو تحديد الحد الأدنى لإصدار المتصفح.


الخلاصة

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

من خلال الاستخدام الصحيح له، يمكن تحسين جودة الكود وقابلية صيانته، خاصة في التطبيقات المعقدة التي تتعامل مع مدخلات المستخدم أو البيانات الديناميكية من مصادر خارجية.


المراجع: