أساسيات JavaScript

العوامل والتعبيرات

45 دقيقة الدرس 4 من 60

ما هي العوامل والتعبيرات؟

العامل هو رمز يخبر JavaScript بإجراء عملية محددة على قيمة واحدة أو أكثر. التعبير هو أي وحدة كود صالحة تحل إلى قيمة. في كل مرة تكتب 5 + 3، فإنك تستخدم عامل الجمع لإنشاء تعبير يقيم إلى 8. فهم العوامل أمر ضروري لأنها أفعال برامجك -- فهي تصف الإجراءات المنفذة على بياناتك.

تمتلك JavaScript مجموعة غنية من العوامل منظمة في فئات: حسابية، تعيينية، مقارنة، منطقية، ثنائية البت، وعدة عوامل ذات أغراض خاصة. في هذا الدرس، سنستكشف كل فئة بعمق، ونتعلم كيف تتفاعل العوامل من خلال الأسبقية والترابط، ونكتشف عوامل JavaScript الحديثة مثل التحقق العدمي والتسلسل الاختياري التي تجعل كودك أكثر إيجازا ومتانة.

العوامل الحسابية

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

مثال: العوامل الحسابية الأساسية

// الجمع (+)
console.log(10 + 5);    // 15
console.log(10 + '5');   // "105" (دمج نصوص!)

// الطرح (-)
console.log(10 - 5);    // 5
console.log(10 - '3');   // 7 (النص "3" يتحول إلى رقم)

// الضرب (*)
console.log(10 * 5);    // 50
console.log(10 * '2');   // 20

// القسمة (/)
console.log(10 / 3);    // 3.3333333333333335
console.log(10 / 0);    // Infinity
console.log(-10 / 0);   // -Infinity
console.log(0 / 0);     // NaN

// باقي القسمة (%)
console.log(10 % 3);    // 1 (باقي قسمة 10 / 3)
console.log(7 % 2);     // 1 (مفيد للتحقق من الزوجي/الفردي)
console.log(-7 % 3);    // -1 (الإشارة تتبع المقسوم)

// الأس (**)
console.log(2 ** 10);   // 1024
console.log(9 ** 0.5);  // 3 (الجذر التربيعي)
console.log(2 ** -1);   // 0.5 (المقلوب)

عوامل الزيادة والنقصان

عاملا الزيادة (++) والنقصان (--) يضيفان أو يطرحان 1 من القيمة. يأتيان بشكلين: بادئ (قبل المتغير) ولاحق (بعد المتغير). الفرق مهم عند استخدامهما ضمن التعبيرات: البادئ يعيد القيمة الجديدة، بينما اللاحق يعيد القيمة الأصلية قبل التعديل.

مثال: الزيادة والنقصان

let a = 5;

// لاحق: يعيد القيمة ثم يزيد
console.log(a++); // 5 (يعيد الأصلية، ثم a تصبح 6)
console.log(a);   // 6

// بادئ: يزيد ثم يعيد القيمة
console.log(++a); // 7 (يزيد أولا، ثم يعيد 7)
console.log(a);   // 7

// نفس المفهوم مع النقصان
let b = 10;
console.log(b--); // 10 (يعيد الأصلية، ثم b تصبح 9)
console.log(--b); // 8 (ينقص أولا، ثم يعيد 8)

// مثال عملي يوضح الفرق
let x = 5;
let y = x++;  // y = 5, x = 6 (لاحق: يعيّن ثم يزيد)
let z = ++x;  // z = 7, x = 7 (بادئ: يزيد ثم يعيّن)

console.log(x, y, z); // 7, 5, 7
نصيحة احترافية: تجنب استخدام عوامل الزيادة/النقصان ضمن التعبيرات المعقدة لأن التمييز بين البادئ واللاحق يمكن أن يجعل الكود مربكا. استخدمها في أسطر مستقلة: count++; في سطر منفصل أوضح بكثير من تضمين count++ داخل تعبير أكبر. العديد من أدلة الأنماط (بما في ذلك دليل Airbnb) توصي باستخدام count += 1 بدلا من count++ للوضوح.

العامل الأحادي الموجب والسالب

العامل الأحادي الموجب (+) والعامل الأحادي السالب (-) يعملان على معامل واحد. العامل الأحادي الموجب هو أسرع طريقة لتحويل قيمة إلى رقم، بينما العامل الأحادي السالب يحول وينفي. هذان مختلفان عن عاملي الجمع والطرح الثنائيين اللذين يعملان على معاملين.

مثال: العوامل الأحادية

// العامل الأحادي الموجب يحول إلى رقم
console.log(+'42');       // 42
console.log(+true);       // 1
console.log(+false);      // 0
console.log(+'');         // 0
console.log(+null);       // 0
console.log(+undefined);  // NaN
console.log(+'hello');    // NaN

// العامل الأحادي السالب يحول وينفي
console.log(-'42');   // -42
console.log(-true);   // -1
console.log(-(-5));   // 5 (نفي مزدوج)

عوامل التعيين

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

مثال: عوامل التعيين

// التعيين الأساسي
let x = 10;

// تعيين الجمع
x += 5;     // x = x + 5 = 15
console.log(x); // 15

// تعيين الطرح
x -= 3;     // x = x - 3 = 12
console.log(x); // 12

// تعيين الضرب
x *= 2;     // x = x * 2 = 24
console.log(x); // 24

// تعيين القسمة
x /= 4;     // x = x / 4 = 6
console.log(x); // 6

// تعيين الباقي
x %= 4;     // x = x % 4 = 2
console.log(x); // 2

// تعيين الأس
x **= 3;    // x = x ** 3 = 8
console.log(x); // 8

// عوامل التعيين المنطقية (ES2021)
let a = null;
a ??= 'default';   // a = a ?? "default"
console.log(a);     // "default" (a كانت null)

let b = 0;
b ||= 42;          // b = b || 42
console.log(b);     // 42 (b كانت كاذبة)

let c = 1;
c &&= 99;          // c = c && 99
console.log(c);     // 99 (c كانت صادقة)

// تعيين دمج النصوص
let greeting = 'Hello';
greeting += ' World';
console.log(greeting); // "Hello World"
ملاحظة: عوامل التعيين المنطقية (??=، ||=، &&=) تم تقديمها في ES2021. هي اختصارات لأنماط شائعة: a ??= b تعيّن فقط إذا كانت a هي null أو undefined، a ||= b تعيّن إذا كانت a كاذبة، وa &&= b تعيّن إذا كانت a صادقة. هذه مفيدة بشكل خاص لتعيين القيم الافتراضية والتحديثات الشرطية.

عوامل المقارنة

عوامل المقارنة تقارن قيمتين وتعيد قيمة منطقية (true أو false). هي أساس كل المنطق الشرطي في برامجك. توفر JavaScript عوامل مقارنة صارمة وفضفاضة، بالإضافة إلى عوامل علائقية للترتيب.

مثال: عوامل المقارنة

// المساواة وعدم المساواة الصارمة (الموصى بها)
console.log(5 === 5);      // true
console.log(5 === '5');    // false (أنواع مختلفة)
console.log(5 !== 3);      // true
console.log(5 !== '5');    // true (أنواع مختلفة)

// المساواة وعدم المساواة الفضفاضة (تجنبها)
console.log(5 == '5');     // true (تحويل أنواع!)
console.log(0 == false);   // true (تحويل أنواع!)
console.log(null == undefined); // true (قاعدة خاصة)
console.log(5 != '5');     // false (تحويل أنواع!)

// أكبر من، أصغر من
console.log(10 > 5);      // true
console.log(10 < 5);      // false
console.log(10 >= 10);    // true
console.log(10 <= 9);     // false

// مقارنة النصوص (معجمية، بنقاط Unicode)
console.log('apple' < 'banana'); // true (a < b)
console.log('Zebra' < 'apple'); // true (Z=90 < a=97)
console.log('100' < '20');     // true (مقارنة نصوص، "1" < "2")

// مقارنة أنواع مختلفة
console.log('10' > 9);    // true (النص "10" يتحول إلى رقم)
console.log(null > 0);    // false
console.log(null == 0);   // false
console.log(null >= 0);   // true (null تتحول إلى 0 للمقارنة)

// مقارنة NaN
console.log(NaN > 0);     // false
console.log(NaN < 0);     // false
console.log(NaN === NaN);  // false
console.log(NaN == NaN);   // false
خطأ شائع: مقارنات النصوص حساسة لحالة الأحرف ومبنية على نقاط Unicode، وليس الترتيب الأبجدي كما يفهمه البشر. الأحرف الكبيرة لها نقاط رمز أقل من الأحرف الصغيرة، لذا 'Zebra' < 'apple' هي true. عند مقارنة النصوص أبجديا، حولها إلى نفس الحالة أولا: 'Zebra'.toLowerCase() < 'apple'.toLowerCase(). للترتيب المراعي للغة، استخدم String.prototype.localeCompare().

العوامل المنطقية

العوامل المنطقية تعمل مع القيم المنطقية وتستخدم لدمج الشروط. لكن في JavaScript، العوامل المنطقية لا تعيد دائما قيما منطقية -- بل تعيد أحد معاملاتها. هذا السلوك يمكّن أنماطا قوية مثل القيم الافتراضية وبنود الحراسة. فهم كيف تعمل العوامل المنطقية فعلا (وليس فقط جداول الحقيقة) أمر حاسم لكتابة JavaScript اصطلاحية.

العامل المنطقي AND (&&)

عامل AND يعيد أول معامل كاذب يواجهه، أو المعامل الأخير إذا كانت جميعها صادقة. يقيم من اليسار إلى اليمين ويتوقف حالما يجد قيمة كاذبة (تقييم الدائرة القصيرة). هذا يعني أن الجانب الأيمن لا يتم تقييمه إطلاقا إذا كان الجانب الأيسر كاذبا.

مثال: العامل المنطقي AND

// السياق المنطقي
console.log(true && true);   // true
console.log(true && false);  // false
console.log(false && true);  // false (الجانب الأيمن لا يُقيَّم)

// يعيد المعامل الفعلي، وليس فقط true/false
console.log('hello' && 'world');  // "world" (كلاهما صادق، يعيد الأخير)
console.log(0 && 'hello');       // 0 (أول قيمة كاذبة)
console.log('' && 'hello');      // "" (أول قيمة كاذبة)
console.log(1 && 2 && 3);       // 3 (الكل صادق، يعيد الأخير)
console.log(1 && 0 && 3);       // 0 (أول كاذب)

// تقييم الدائرة القصيرة
let user = null;
// هذا آمن -- الجانب الأيمن لا يُقيَّم عندما تكون user هي null
let name = user && user.name;
console.log(name); // null (وليس TypeError!)

// نمط الحراسة
function greet(user) {
    user && console.log(`مرحبا، ${user.name}`);
    // ينفذ console.log فقط إذا كان user صادقا
}

greet({ name: 'Alice' }); // "مرحبا، Alice"
greet(null);              // لا يحدث شيء (بدون خطأ)

العامل المنطقي OR (||)

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

مثال: العامل المنطقي OR

// السياق المنطقي
console.log(true || false);  // true
console.log(false || true);  // true
console.log(false || false); // false

// يعيد المعامل الفعلي
console.log('hello' || 'world');   // "hello" (أول صادق)
console.log('' || 'default');      // "default" (الأول كاذب)
console.log(0 || 42);             // 42 (الأول كاذب)
console.log(null || undefined || 'found'); // "found"
console.log(null || 0 || '');      // "" (الكل كاذب، يعيد الأخير)

// نمط القيم الافتراضية
function greet(name) {
    name = name || 'مجهول';
    console.log(`مرحبا، ${name}!`);
}

greet('Alice');    // "مرحبا، Alice!"
greet('');         // "مرحبا، مجهول!" (النص الفارغ كاذب!)
greet(undefined);  // "مرحبا، مجهول!"

// مشكلة: || تعامل 0 و "" و false ككاذبة
let port = 0;
let serverPort = port || 3000;
console.log(serverPort); // 3000 (لكن 0 كان مقصودا!)

العامل المنطقي NOT (!)

عامل NOT يحول معامله إلى قيمة منطقية ثم ينفيها. يعيد دائما قيمة منطقية، بخلاف AND و OR اللذين يعيدان معاملا. النفي المزدوج (!!) هو نمط شائع لتحويل أي قيمة صراحة إلى معادلها المنطقي.

مثال: العامل المنطقي NOT

// النفي الأساسي
console.log(!true);    // false
console.log(!false);   // true
console.log(!0);       // true (0 كاذبة)
console.log(!'');      // true (النص الفارغ كاذب)
console.log(!'hello'); // false (النص غير الفارغ صادق)
console.log(!null);    // true (null كاذبة)
console.log(!undefined); // true

// النفي المزدوج (!!) للتحويل المنطقي
console.log(!!'hello'); // true
console.log(!!0);       // false
console.log(!!null);    // false
console.log(!!{});      // true
console.log(!!1);       // true

// استخدام عملي في الشروط
let items = [];
if (!items.length) {
    console.log('لم يتم العثور على عناصر'); // هذا يعمل (0 كاذبة، !0 صادقة)
}

عامل التحقق العدمي (??)

عامل التحقق العدمي (??) تم تقديمه في ES2020 لحل مشكلة محددة مع عامل OR. بينما || يعيد الجانب الأيمن لأي قيمة كاذبة (بما في ذلك 0 و'' وfalse)، فإن ?? يعيد الجانب الأيمن فقط عندما يكون الجانب الأيسر null أو undefined. هذا يجعله مثاليا لتوفير قيم افتراضية عندما تريد الحفاظ على القيم الكاذبة المقصودة مثل 0 أو النصوص الفارغة.

مثال: التحقق العدمي (??) مقابل OR (||)

// المشكلة مع ||
let count = 0;
console.log(count || 10);  // 10 (خطأ! 0 هو عدد صالح)
console.log(count ?? 10);  // 0 (صحيح! 0 ليست null/undefined)

let text = '';
console.log(text || 'default');  // "default" (خطأ! "" قد تكون مقصودة)
console.log(text ?? 'default');  // "" (صحيح! "" ليست null/undefined)

let isActive = false;
console.log(isActive || true);  // true (خطأ! false كانت مقصودة)
console.log(isActive ?? true);  // false (صحيح! false ليست null/undefined)

// ?? تعمل فقط مع null و undefined
console.log(null ?? 'بديل');      // "بديل"
console.log(undefined ?? 'بديل'); // "بديل"
console.log(0 ?? 'بديل');         // 0
console.log('' ?? 'بديل');        // ""
console.log(false ?? 'بديل');     // false
console.log(NaN ?? 'بديل');       // NaN

// استخدام عملي: الإعدادات مع القيم الافتراضية
function createServer(config) {
    let port = config.port ?? 3000;
    let host = config.host ?? 'localhost';
    let debug = config.debug ?? false;

    console.log(`الخادم: ${host}:${port}, التصحيح: ${debug}`);
}

createServer({ port: 0, host: '', debug: false });
// "الخادم: :0, التصحيح: false" -- كل القيم المقصودة محفوظة!
ملاحظة: لا يمكنك الجمع مباشرة بين ?? و&& أو || بدون أقواس. التعبير a || b ?? c هو خطأ نحوي لأن علاقة الأسبقية بين هذه العوامل غامضة. يجب استخدام الأقواس: (a || b) ?? c أو a || (b ?? c).

عامل التسلسل الاختياري (?.)

عامل التسلسل الاختياري (?.)، الذي تم تقديمه في ES2020، يسمح لك بالوصول الآمن إلى خصائص الكائنات المتداخلة بعمق دون التحقق يدويا من كل مستوى للتأكد من أنه ليس null أو undefined. إذا كان أي جزء من السلسلة هو null أو undefined، يقوم التعبير بأكمله بالدائرة القصيرة ويعيد undefined بدلا من إلقاء TypeError. هذا العامل يبسط بشكل كبير الكود الذي يعمل مع هياكل بيانات معقدة وربما غير مكتملة.

مثال: التسلسل الاختياري

let user = {
    name: 'Alice',
    address: {
        street: '123 Main St',
        city: 'Springfield'
    },
    getEmail() {
        return 'alice@example.com';
    }
};

// بدون التسلسل الاختياري (الطريقة القديمة)
let zipCode;
if (user && user.address && user.address.zip) {
    zipCode = user.address.zip;
}

// مع التسلسل الاختياري (نظيف وموجز)
let zip = user?.address?.zip;
console.log(zip); // undefined (بدون خطأ!)

// يعمل مع الخصائص المتداخلة
console.log(user?.address?.city);   // "Springfield"
console.log(user?.phone?.number);   // undefined

// يعمل مع الدوال
console.log(user?.getEmail());       // "alice@example.com"
console.log(user?.getNickname?.());  // undefined (الدالة غير موجودة)

// يعمل مع فهرسة المصفوفات
let users = [{ name: 'Alice' }, { name: 'Bob' }];
console.log(users?.[0]?.name);  // "Alice"
console.log(users?.[5]?.name);  // undefined

// الجمع مع التحقق العدمي
let displayName = user?.nickname ?? 'مستخدم غير معروف';
console.log(displayName); // "مستخدم غير معروف"

// مثال واقعي: معالجة استجابة API
function displayUserCity(response) {
    let city = response?.data?.user?.address?.city ?? 'المدينة غير متوفرة';
    console.log(city);
}

displayUserCity({ data: { user: { address: { city: 'Austin' } } } });
// "Austin"

displayUserCity({ data: { user: {} } });
// "المدينة غير متوفرة"

displayUserCity(null);
// "المدينة غير متوفرة"
نصيحة احترافية: التسلسل الاختياري مصمم للوصول إلى خصائص قد لا تكون موجودة. لا تفرط في استخدامه مع خصائص يجب أن تكون موجودة دائما -- إذا كان user يجب أن يكون لديه دائما خاصية name، فكتابة user?.name تخفي أخطاء محتملة. استخدم التسلسل الاختياري للبيانات الاختيارية حقا مثل استجابات API وكائنات الإعدادات أو المدخلات التي قدمها المستخدم حيث قد تكون بعض الحقول مفقودة.

العامل الثلاثي (? :)

العامل الثلاثي (يسمى أيضا العامل الشرطي) هو العامل الوحيد في JavaScript الذي يأخذ ثلاثة معاملات. يوفر طريقة موجزة لكتابة عبارات if...else البسيطة كتعبيرات. الصيغة هي: الشرط ? القيمة_إذا_صحيح : القيمة_إذا_خطأ. لأنه تعبير (وليس عبارة)، يمكنك استخدامه داخل القوالب النصية ووسائط الدوال وتعيينات المتغيرات وعبارات الإرجاع.

مثال: العامل الثلاثي

// الثلاثي الأساسي
let age = 20;
let status = age >= 18 ? 'بالغ' : 'قاصر';
console.log(status); // "بالغ"

// مكافئ if...else
let status2;
if (age >= 18) {
    status2 = 'بالغ';
} else {
    status2 = 'قاصر';
}

// الثلاثي في القوالب النصية
let score = 85;
console.log(`أنت ${score >= 60 ? 'نجحت في' : 'رسبت في'} الامتحان`);
// "أنت نجحت في الامتحان"

// الثلاثي في استدعاءات الدوال
function greet(name) {
    console.log(`مرحبا، ${name ? name : 'غريب'}!`);
}

greet('Alice');  // "مرحبا، Alice!"
greet('');       // "مرحبا، غريب!"

// الثلاثي المتداخل (استخدم باعتدال!)
let grade = score >= 90 ? 'A'
          : score >= 80 ? 'B'
          : score >= 70 ? 'C'
          : score >= 60 ? 'D'
          : 'F';
console.log(grade); // "B"

// الثلاثي مع الآثار الجانبية (غير موصى به)
let x = 5;
x > 3 ? console.log('كبير') : console.log('صغير');
// الأفضل: استخدم if...else للآثار الجانبية
خطأ شائع: تداخل العوامل الثلاثية أكثر من مستوى واحد يجعل الكود صعب القراءة والصيانة جدا. إذا وجدت نفسك تكتب ثلاثيات متداخلة، أعد الهيكلة إلى سلسلة if...else if...else أو عبارة switch. العامل الثلاثي الأفضل استخداما للتعيينات الشرطية البسيطة أحادية المستوى: let result = condition ? valueA : valueB;

العوامل الثنائية البت

العوامل الثنائية البت تعمل على التمثيلات الثنائية (على مستوى البت) للأرقام. تعامل معاملاتها كتسلسلات من أعداد صحيحة 32 بت وتجري عمليات على كل بت مقابل. بينما العوامل الثنائية البت أقل شيوعا في تطوير الويب اليومي، تظهر في كود حرج الأداء وأنظمة الأعلام ومعالجة الألوان والخوارزميات منخفضة المستوى.

مثال: العوامل الثنائية البت

// AND الثنائي (&) -- كلا البتين يجب أن يكونا 1
console.log(5 & 3);   // 1
// 5 = 101
// 3 = 011
// & = 001 = 1

// OR الثنائي (|) -- بت واحد على الأقل يجب أن يكون 1
console.log(5 | 3);   // 7
// 5 = 101
// 3 = 011
// | = 111 = 7

// XOR الثنائي (^) -- بت واحد بالضبط يجب أن يكون 1
console.log(5 ^ 3);   // 6
// 5 = 101
// 3 = 011
// ^ = 110 = 6

// NOT الثنائي (~) -- يعكس كل البتات
console.log(~5);   // -6
// ~n = -(n + 1)

// الإزاحة لليسار (<<) -- يزيح البتات لليسار، يملأ بـ 0
console.log(5 << 1);  // 10 (فعليا يضرب في 2)
console.log(5 << 2);  // 20 (يضرب في 4)

// الإزاحة لليمين (>>) -- يزيح البتات لليمين، يحافظ على الإشارة
console.log(20 >> 1); // 10 (فعليا يقسم على 2)
console.log(20 >> 2); // 5 (يقسم على 4)

// الإزاحة لليمين بدون إشارة (>>>) -- يزيح لليمين، يملأ بـ 0
console.log(-1 >>> 0); // 4294967295 (كل 32 بت محددة إلى 1)

// استخدام عملي: تحويل سريع إلى عدد صحيح
console.log(3.7 | 0);   // 3 (يقطع العشري)
console.log(-3.7 | 0);  // -3

// استخدام عملي: أعلام الصلاحيات
const READ = 1;    // 001
const WRITE = 2;   // 010
const EXECUTE = 4; // 100

let permissions = READ | WRITE; // 011 = 3
console.log(permissions & READ);    // 1 (صادق -- لديه قراءة)
console.log(permissions & EXECUTE); // 0 (كاذب -- لا تنفيذ)

// إضافة صلاحية
permissions = permissions | EXECUTE; // 111 = 7

// إزالة صلاحية
permissions = permissions & ~WRITE;  // 101 = 5
console.log(permissions & WRITE);    // 0 (الكتابة أزيلت)
ملاحظة: العوامل الثنائية البت تحول معاملاتها إلى أعداد صحيحة موقعة 32 بت قبل إجراء العمليات. هذا يعني أنها تقطع الأماكن العشرية ولا يمكنها العمل مع أرقام أكبر من 2^31 - 1 (2,147,483,647) أو أصغر من -2^31. في معظم تطوير الويب، نادرا ما ستحتاج العوامل الثنائية البت، لكن فهمها يساعدك في قراءة كود مطورين آخرين والعمل مع البيانات الثنائية.

تقييم الدائرة القصيرة

تقييم الدائرة القصيرة هو سلوك أساسي لعاملي AND المنطقي (&&) و OR المنطقي (||). عندما يمكن تحديد نتيجة تعبير منطقي من المعامل الأول وحده، لا يتم تقييم المعامل الثاني أبدا. هذا ليس مجرد تحسين -- إنه ميزة يمكنك استخدامها لكتابة كود أكثر أمانا وإيجازا.

مثال: أنماط تقييم الدائرة القصيرة

// AND تقطع الدائرة عند أول قيمة كاذبة
false && console.log('هذا لا يعمل أبدا');
true && console.log('هذا يعمل');

// OR تقطع الدائرة عند أول قيمة صادقة
true || console.log('هذا لا يعمل أبدا');
false || console.log('هذا يعمل');

// الوصول الآمن للخصائص (قبل وجود التسلسل الاختياري)
let user = null;
let name = user && user.name; // null (بدون TypeError)

// تنفيذ دالة مشروط
function processOrder(order) {
    // التحقق فقط إذا كانت الدالة موجودة
    order.validate && order.validate();

    // التسجيل فقط في وضع التصحيح
    order.debug && console.log('معالجة الطلب:', order.id);
}

// القيم الافتراضية مع OR
function createElement(tag, className) {
    tag = tag || 'div';
    className = className || 'default';
    console.log(`<${tag} class="${className}">`);
}

createElement('span', 'highlight'); // <span class="highlight">
createElement();                     // <div class="default">

// دمج الأنماط
function getUserDisplay(user) {
    return (user && user.displayName) || (user && user.email) || 'ضيف';
}

console.log(getUserDisplay({ displayName: 'Alice' })); // "Alice"
console.log(getUserDisplay({ email: 'a@b.com' }));    // "a@b.com"
console.log(getUserDisplay(null));                      // "ضيف"

أسبقية العوامل

عندما يحتوي تعبير على عوامل متعددة، تحتاج JavaScript لتحديد أي العمليات تنفذ أولا. أسبقية العوامل تحدد هذا الترتيب. العوامل ذات الأسبقية الأعلى تُقيَّم قبل العوامل ذات الأسبقية الأقل. عندما تكون للعوامل نفس الأسبقية، يحدد الترابط (من اليسار لليمين أو من اليمين لليسار) الترتيب. فهم الأسبقية يساعدك على التنبؤ بكيفية تقييم التعبيرات ومتى تستخدم الأقواس للوضوح.

مثال: أسبقية العوامل

// الضرب له أسبقية أعلى من الجمع
console.log(2 + 3 * 4);   // 14 (وليس 20)
console.log((2 + 3) * 4); // 20 (الأقواس تتجاوز)

// ترتيب الأسبقية (من الأعلى للأقل، مبسط):
// 1.  ()          -- التجميع (الأعلى)
// 2.  ?.          -- التسلسل الاختياري
// 3.  ++ --       -- الزيادة/النقصان
// 4.  ! ~ + -     -- العوامل الأحادية، typeof، void، delete
// 5.  **          -- الأس
// 6.  * / %       -- الضرب والقسمة والباقي
// 7.  + -         -- الجمع والطرح
// 8.  << >> >>>  -- الإزاحات الثنائية
// 9.  < > <= >=   -- العلائقية، in، instanceof
// 10. == != === !== -- المساواة
// 11. &           -- AND الثنائي
// 12. ^           -- XOR الثنائي
// 13. |           -- OR الثنائي
// 14. &&          -- AND المنطقي
// 15. ||          -- OR المنطقي
// 16. ??          -- التحقق العدمي
// 17. ? :         -- الثلاثي
// 18. = += -= إلخ -- التعيين (الأقل)

// أمثلة واقعية
let result = 2 + 3 * 4 ** 2;
// الخطوة 1: 4 ** 2 = 16  (الأس أولا)
// الخطوة 2: 3 * 16 = 48  (الضرب ثانيا)
// الخطوة 3: 2 + 48 = 50  (الجمع أخيرا)
console.log(result); // 50

// أسبقية العوامل المنطقية
console.log(true || false && false);  // true
// && لها أسبقية أعلى من ||
// يُقيَّم كـ: true || (false && false)
// = true || false
// = true

// NOT لها أعلى أسبقية بين العوامل المنطقية
console.log(!true && false);  // false
// يُقيَّم كـ: (!true) && false = false && false = false

// التعيين له أسبقية منخفضة جدا
let a, b, c;
a = b = c = 5; // ترابط من اليمين لليسار
// c = 5، ثم b = 5، ثم a = 5
console.log(a, b, c); // 5 5 5
نصيحة احترافية: لا تحتاج لحفظ جدول الأسبقية بالكامل. بدلا من ذلك، اتبع قاعدتين: (1) استخدم الأقواس كلما لم يكن ترتيب التقييم واضحا فورا. (2) قسم التعبيرات المعقدة إلى عبارات منفصلة بأسماء متغيرات وصفية. الكود الذي يُقرأ كنثر دائما أفضل من الأسطر الذكية الواحدة التي تتطلب جدول أسبقية لفهمها.

عامل الفاصلة

عامل الفاصلة يقيم كل معامل من اليسار لليمين ويعيد قيمة المعامل الأخير. هو العامل ذو أقل أسبقية في JavaScript (حتى أقل من التعيين). بينما نادرا ما يُستخدم في الكود العام، يظهر في حلقات for وأحيانا في الكود المصغر.

مثال: عامل الفاصلة

// عامل الفاصلة يعيد القيمة الأخيرة
let x = (1, 2, 3);
console.log(x); // 3

// الاستخدام الشائع في حلقات for
for (let i = 0, j = 10; i < j; i++, j--) {
    console.log(i, j);
}
// 0 10
// 1 9
// 2 8
// 3 7
// 4 6

// بدون أقواس، الفاصلة لها أسبقية أقل من التعيين
let a = 1, b = 2; // هذا تصريح متغيرات، وليس عامل فاصلة
// مقابل
let c;
c = (1, 2); // عامل الفاصلة: يقيم 1 ثم 2، يعيد 2
console.log(c); // 2

عاملا typeof و delete

غطينا typeof بالتفصيل في الدرس السابق. عاملان أحاديان آخران يستحقان الذكر هما delete (يزيل خاصية من كائن) وvoid (يقيم تعبيرا ويعيد undefined).

مثال: عاملا delete و void

// delete يزيل خصائص الكائنات
let user = { name: 'Alice', age: 30, role: 'admin' };
delete user.role;
console.log(user); // { name: "Alice", age: 30 }
console.log(user.role); // undefined

// delete لا يعمل على المتغيرات
let x = 5;
// delete x; // لا تأثير في الوضع الصارم

// delete يعيد true إذا نجح
console.log(delete user.age); // true
console.log(delete user.nonexistent); // true (غير موجود أصلا)

// عامل void يعيد undefined
console.log(void 0);         // undefined
console.log(void 'hello');   // undefined
console.log(void (2 + 3));   // undefined

// يُستخدم void أحيانا لضمان undefined
if (value === void 0) {
    console.log('القيمة هي undefined');
}

عاملا النشر والباقي (...)

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

مثال: النشر والباقي

// النشر: توسيع المصفوفات
let numbers = [1, 2, 3];
let more = [...numbers, 4, 5, 6];
console.log(more); // [1, 2, 3, 4, 5, 6]

// النشر: نسخ المصفوفات
let original = [1, 2, 3];
let copy = [...original];
copy.push(4);
console.log(original); // [1, 2, 3] (لم تتغير)
console.log(copy);     // [1, 2, 3, 4]

// النشر: دمج الكائنات
let defaults = { color: 'blue', size: 'medium', border: true };
let custom = { size: 'large', weight: 'bold' };
let merged = { ...defaults, ...custom };
console.log(merged);
// { color: "blue", size: "large", border: true, weight: "bold" }

// النشر: وسائط الدوال
let values = [5, 10, 15, 3, 8];
console.log(Math.max(...values)); // 15

// الباقي: جمع وسائط الدوال
function sum(...numbers) {
    return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15

// الباقي: التفكيك
let [first, second, ...remaining] = [1, 2, 3, 4, 5];
console.log(first);     // 1
console.log(second);    // 2
console.log(remaining); // [3, 4, 5]

// الباقي: تفكيك الكائنات
let { name, ...otherProps } = { name: 'Alice', age: 30, role: 'admin' };
console.log(name);       // "Alice"
console.log(otherProps); // { age: 30, role: "admin" }

دمج العوامل: أنماط واقعية

في الممارسة العملية، نادرا ما تُستخدم العوامل بمعزل. إليك أنماط شائعة تجمع بين عوامل متعددة لحل مشاكل البرمجة الحقيقية بأناقة.

مثال: أنماط العوامل الشائعة

// النمط 1: الوصول الآمن للخصائص مع قيمة افتراضية
function getConfig(options) {
    let timeout = options?.timeout ?? 5000;
    let retries = options?.retries ?? 3;
    let verbose = options?.verbose ?? false;
    return { timeout, retries, verbose };
}

console.log(getConfig({ timeout: 0 }));
// { timeout: 0, retries: 3, verbose: false }

console.log(getConfig(null));
// { timeout: 5000, retries: 3, verbose: false }

// النمط 2: تبديل القيمة المنطقية
let isVisible = true;
isVisible = !isVisible; // false
isVisible = !isVisible; // true

// النمط 3: تبديل المتغيرات بدون متغير مؤقت
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2, 1

// النمط 4: تقييد قيمة ضمن نطاق
function clamp(value, min, max) {
    return Math.max(min, Math.min(max, value));
}

console.log(clamp(15, 0, 10));  // 10
console.log(clamp(-5, 0, 10));  // 0
console.log(clamp(5, 0, 10));   // 5

// النمط 5: التحقق من زوجي أو فردي
let num = 7;
console.log(num % 2 === 0 ? 'زوجي' : 'فردي'); // "فردي"

// النمط 6: التحويل إلى عدد صحيح (طرق متعددة)
let float = 3.7;
console.log(Math.floor(float));   // 3 (يقرب للأسفل)
console.log(Math.ceil(float));    // 4 (يقرب للأعلى)
console.log(Math.trunc(float));   // 3 (يزيل العشري)
console.log(float | 0);           // 3 (اقتطاع ثنائي)
console.log(~~float);             // 3 (NOT ثنائي مزدوج)

// النمط 7: سلسلة شروط مع إرجاع مبكر
function processPayment(order) {
    if (!order) return { error: 'لم يتم تقديم طلب' };
    if (!order.items?.length) return { error: 'سلة فارغة' };
    if (!(order.total > 0)) return { error: 'المجموع غير صالح' };
    if (!order.paymentMethod) return { error: 'لا توجد طريقة دفع' };

    return { success: true, orderId: order.id };
}

تمرين عملي

ابنِ وحدة آلة حاسبة مصغرة تُظهر فهمك لجميع فئات العوامل. أنشئ الدوال التالية: (1) calculate(a, operator, b) التي تأخذ رقمين ونص عامل ('+'، '-'، '*'، '/'، '%'، '**') وتعيد النتيجة، مع معالجة القسمة على صفر والعوامل غير الصالحة برسائل خطأ وصفية. (2) compareValues(a, b) التي تعيد كائنا يصف العلاقة بين قيمتين: { equal, strictEqual, greaterThan, lessThan, type_a, type_b }. (3) bitwiseInfo(n) التي تأخذ رقما وتعيد كائنا يحتوي: التمثيل الثنائي كنص، ونتيجة الإزاحة لليسار بـ 1، ونتيجة الإزاحة لليمين بـ 1، و NOT الثنائي. (4) safeAccess(obj, path, defaultValue) التي تصل بأمان إلى خاصية متداخلة باستخدام نص مسار مفصول بنقاط (مثل 'user.address.city') وتعيد defaultValue إذا كان أي جزء من المسار null أو undefined. لا تستخدم التسلسل الاختياري في هذه الدالة -- نفذ الوصول الآمن يدويا باستخدام حلقة وتقييم الدائرة القصيرة. اختبر جميع الدوال الأربع بمدخلات عادية وحالات حدودية.

ES
Edrees Salih
منذ 11 ساعة

We are still cooking the magic in the way!