We are still cooking the magic in the way!
JavaScript المتقدم (ES6+)
عوامل النشر والباقي (Spread & Rest)
عوامل النشر والباقي (Spread & Rest)
عوامل النشر (...) والباقي (Rest) هي ميزات قوية في ES6+ تستخدم نفس الصيغة ولكنها تخدم أغراضاً مختلفة. إنها تجعل العمل مع المصفوفات والكائنات ومعاملات الدوال أكثر أناقة وكفاءة.
عامل النشر للمصفوفات
عامل النشر يوسع المصفوفة إلى عناصر فردية. إنه مفيد للغاية للنسخ والدمج ومعالجة المصفوفات:
// نسخ المصفوفات (نسخة سطحية)
const original = [1, 2, 3];
const copy = [...original];
console.log(copy); // [1, 2, 3]
// دمج المصفوفات
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
// إضافة عناصر أثناء النشر
const numbers = [2, 3, 4];
const extended = [1, ...numbers, 5];
console.log(extended); // [1, 2, 3, 4, 5]
نصيحة: عامل النشر ينشئ نسخة سطحية. بالنسبة للمصفوفات أو الكائنات المتداخلة، يتم نسخ المراجع المتداخلة، وليس القيم المتداخلة نفسها.
عامل النشر مع معاملات الدالة
يمكنك استخدام النشر لتمرير عناصر المصفوفة كمعاملات فردية للدالة:
function add(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
// الطريقة القديمة
console.log(add.apply(null, numbers)); // 6
// طريقة ES6+ مع النشر
console.log(add(...numbers)); // 6
// دوال Math
const scores = [85, 92, 78, 95, 88];
console.log(Math.max(...scores)); // 95
console.log(Math.min(...scores)); // 78
عامل النشر للكائنات
قدم ES2018 نشر الكائنات، مما يسمح لك بنسخ ودمج الكائنات بسهولة:
// نسخ الكائنات (نسخة سطحية)
const person = { name: 'John', age: 30 };
const personCopy = { ...person };
console.log(personCopy); // { name: 'John', age: 30 }
// دمج الكائنات
const defaults = { theme: 'light', language: 'en' };
const userSettings = { language: 'ar', fontSize: 16 };
const settings = { ...defaults, ...userSettings };
console.log(settings);
// { theme: 'light', language: 'ar', fontSize: 16 }
// إضافة/استبدال الخصائص
const user = { name: 'Alice', role: 'user' };
const admin = { ...user, role: 'admin', permissions: ['read', 'write'] };
console.log(admin);
// { name: 'Alice', role: 'admin', permissions: ['read', 'write'] }
الترتيب مهم: عند دمج الكائنات، تتجاوز خصائص الكائنات اللاحقة الخصائص السابقة. في المثال أعلاه،
language: 'ar' يتجاوز language: 'en'.
معاملات الباقي في الدوال
عامل الباقي (...) يجمع عناصر متعددة في مصفوفة. عند استخدامه في معاملات الدالة، يُطلق عليه "معاملات الباقي":
// جمع المعاملات المتبقية
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
// دمج المعاملات العادية مع الباقي
function introduce(greeting, ...names) {
return `${greeting}, ${names.join(' and ')}!`;
}
console.log(introduce('Hello', 'Alice')); // "Hello, Alice!"
console.log(introduce('Hello', 'Alice', 'Bob', 'Charlie'));
// "Hello, Alice and Bob and Charlie!"
مهم: يجب أن تكون معاملات الباقي آخر معامل في الدالة. لا يمكن أن يكون لديك معاملات بعد معامل الباقي.
الباقي في التفكيك
يمكن أيضاً استخدام الباقي في التفكيك لجمع العناصر المتبقية:
// تفكيك المصفوفة مع الباقي
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
// تفكيك الكائن مع الباقي
const person = {
name: 'John',
age: 30,
city: 'New York',
country: 'USA'
};
const { name, ...details } = person;
console.log(name); // "John"
console.log(details); // { age: 30, city: 'New York', country: 'USA' }
النشر مقابل الباقي: فهم الفرق
النشر (يوسع):
- يُستخدم حيث يُتوقع قيم متعددة
- في استدعاءات الدوال: func(...arr)
- في صيغ المصفوفات: [...arr1, ...arr2]
- في صيغ الكائنات: {...obj1, ...obj2}
الباقي (يجمع):
- يُستخدم حيث تحتاج قيم متعددة إلى جمعها في واحدة
- في معاملات الدالة: function(...args)
- في التفكيك: const [a, ...rest] = array
الاستنساخ مقابل النسخ السطحي
// نسخة سطحية - الكائنات المتداخلة تشارك المراجع
const original = {
name: 'John',
address: { city: 'New York' }
};
const copy = { ...original };
copy.address.city = 'Boston';
console.log(original.address.city); // "Boston" (متأثر!)
// حل النسخ العميق
const deepCopy = JSON.parse(JSON.stringify(original));
// أو استخدم مكتبة مثل cloneDeep من lodash
حالات الاستخدام العملية
// 1. تحويل NodeList إلى مصفوفة
const divs = document.querySelectorAll('div');
const divArray = [...divs];
// 2. إزالة التكرارات من المصفوفة
const numbers = [1, 2, 2, 3, 3, 4];
const unique = [...new Set(numbers)];
console.log(unique); // [1, 2, 3, 4]
// 3. النشر الشرطي
const isAdmin = true;
const user = {
name: 'Alice',
...(isAdmin && { role: 'admin', permissions: ['all'] })
};
// 4. عمليات المصفوفة غير القابلة للتغيير
const todos = ['Task 1', 'Task 2'];
const addTodo = (todos, newTodo) => [...todos, newTodo];
const removeTodo = (todos, index) => [
...todos.slice(0, index),
...todos.slice(index + 1)
];
الأنماط الشائعة
// الإضافة في البداية والنهاية
const arr = [2, 3, 4];
const prepended = [1, ...arr]; // [1, 2, 3, 4]
const appended = [...arr, 5]; // [2, 3, 4, 5]
// الإدراج في المنتصف
const insert = (arr, index, item) => [
...arr.slice(0, index),
item,
...arr.slice(index)
];
// الدمج مع الأولوية
const config = {
...defaultConfig,
...userConfig,
...overrides
};
// دالة مع معاملات اختيارية
function createUser(name, options = {}) {
return {
name,
role: 'user',
active: true,
...options // تجاوز الافتراضيات
};
}
تمرين تطبيقي:
المهمة: أنشئ دوال باستخدام عوامل النشر والباقي:
- اكتب دالة
mergeتقبل أي عدد من المصفوفات وتُرجع مصفوفة واحدة مدمجة - أنشئ دالة
filterObjectتزيل مفاتيح محددة من كائن - ابنِ دالة
loggerتقبل مستوى السجل وأي عدد من الرسائل
الحل:
// 1. دمج المصفوفات
function merge(...arrays) {
return [].concat(...arrays);
}
console.log(merge([1, 2], [3, 4], [5])); // [1, 2, 3, 4, 5]
// 2. تصفية الكائن
function filterObject(obj, ...keysToRemove) {
const filtered = { ...obj };
keysToRemove.forEach(key => delete filtered[key]);
return filtered;
}
const user = { name: 'John', age: 30, password: 'secret' };
console.log(filterObject(user, 'password')); // { name: 'John', age: 30 }
// 3. السجل
function logger(level, ...messages) {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] ${level.toUpperCase()}:`, ...messages);
}
logger('info', 'User logged in', 'ID: 123');
اعتبارات الأداء
ملاحظة: بينما النشر مريح، كن واعياً للأداء مع المصفوفات أو الكائنات الكبيرة. للبيانات الكبيرة جداً أو العمليات المتكررة، فكر في بدائل مثل
Array.concat() أو Object.assign().
الملخص
في هذا الدرس، تعلمت:
- عامل النشر يوسع المصفوفات والكائنات إلى عناصر فردية
- معاملات الباقي تجمع معاملات متعددة في مصفوفة
- النشر ينشئ نسخاً سطحية من المصفوفات والكائنات
- يجب أن يكون الباقي آخر معامل في التفكيك أو الدوال
- كلا العاملين يستخدمان نفس صيغة
...لكنهما يخدمان أغراضاً متعاكسة - التطبيقات العملية تشمل الدمج والنسخ ومعاملات الدوال
التالي: في الدرس التالي، سنستكشف صيغ الكائنات المحسّنة وكيف تبسط إنشاء الكائنات في ES6+!