تكرار المصفوفات: forEach و map و filter و reduce
مقدمة في دوال تكرار المصفوفات
تاتي مصفوفات JavaScript مع مجموعة قوية من الدوال المدمجة التي تتيح لك التكرار على العناصر وتحويل البيانات واستخراج نتائج ذات معنى -- كل ذلك دون كتابة حلقات for التقليدية. تسمى هذه الدوال دوال الترتيب العالي لانها تقبل دوال اخرى كمعاملات. اتقان هذه الدوال ضروري لكتابة كود JavaScript نظيف وقابل للقراءة والصيانة. في تطوير JavaScript الحديث تعتبر دوال تكرار المصفوفات العمود الفقري لمعالجة البيانات سواء كنت تقوم بتصفية المنتجات في تطبيق تجارة الكترونية او حساب الاجماليات في سلة التسوق او تحويل استجابات واجهات برمجة التطبيقات الى تنسيق يمكن لمكونات واجهة المستخدم عرضه.
قبل وجود هذه الدوال اعتمد المطورون على حلقات for والتتبع اليدوي للفهرس للتكرار على المصفوفات. بينما تعمل حلقات for بشكل جيد تماما فان دوال التكرار الوظيفية تقدم مزايا كبيرة: فهي اكثر تعبيرا وتقلل فرصة اخطاء الفهرس الزائد بواحد وتشجع انماط البيانات غير القابلة للتغيير التي تجعل كودك اسهل في الفهم. كل دالة تخدم غرضا محددا وفهم متى تستخدم اي دالة مهارة تفصل مطوري JavaScript المبتدئين عن المتوسطين.
دالة forEach
تنفذ دالة forEach دالة محددة مرة واحدة لكل عنصر في المصفوفة. انها ابسط دالة تكرار وتعمل كبديل مباشر لحلقة for الاساسية. على عكس الدوال الاخرى التي سنغطيها لا تعيد forEach مصفوفة جديدة -- بل تنفذ دالة لكل عنصر وتعيد undefined.
الصيغة الاساسية
تاخذ دالة forEach دالة رد اتصال تستقبل حتى ثلاث معاملات: العنصر الحالي والفهرس الحالي والمصفوفة الكاملة التي يتم التكرار عليها.
مثال: صيغة forEach الاساسية
const fruits = ['apple', 'banana', 'cherry', 'date'];
// الاستخدام الاساسي -- العنصر فقط
fruits.forEach(function(fruit) {
console.log(fruit);
});
// المخرج: apple, banana, cherry, date
// باستخدام صيغة الدالة السهمية
fruits.forEach(fruit => console.log(fruit));
// باستخدام معامل الفهرس
fruits.forEach(function(fruit, index) {
console.log(index + ': ' + fruit);
});
// المخرج: 0: apple, 1: banana, 2: cherry, 3: date
// باستخدام المعاملات الثلاثة
fruits.forEach(function(fruit, index, array) {
console.log(fruit + ' هو العنصر ' + (index + 1) + ' من ' + array.length);
});
// المخرج: apple هو العنصر 1 من 4, banana هو العنصر 2 من 4, ...
متى تستخدم forEach
استخدم forEach عندما تحتاج لتنفيذ تاثير جانبي لكل عنصر -- مثل التسجيل او تحديث DOM او ارسال احداث التحليلات او دفع قيم الى بنية بيانات خارجية. من المهم فهم ان forEach تعيد دائما undefined لذلك لا يمكنك ربطها مع دوال مصفوفات اخرى. اذا كنت تحتاج لتحويل البيانات او انتاج مصفوفة جديدة استخدم map بدلا من ذلك.
مثال: forEach لتحديثات DOM
const menuItems = ['الرئيسية', 'حول', 'الخدمات', 'اتصل بنا'];
const navList = document.querySelector('#nav-list');
menuItems.forEach(function(item) {
const li = document.createElement('li');
li.textContent = item;
navList.appendChild(li);
});
forEach مبكرا. اذا كنت تحتاج لايقاف التكرار عند تحقق شرط معين استخدم حلقة for عادية او for...of او دوال some او every بدلا من ذلك.دالة map
تنشئ دالة map مصفوفة جديدة عن طريق استدعاء دالة محددة على كل عنصر في المصفوفة الاصلية. ستكون المصفوفة الجديدة دائما بنفس طول المصفوفة الاصلية. هذه هي الدالة المفضلة لتحويل البيانات -- اخذ مصفوفة من القيم بشكل واحد وانتاج مصفوفة من القيم بشكل اخر.
الصيغة الاساسية والتحويل
مثال: تحويلات map
const numbers = [1, 2, 3, 4, 5];
// مضاعفة كل رقم
const doubled = numbers.map(function(num) {
return num * 2;
});
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5] -- الاصلية لم تتغير
// التحويل الى نصوص
const strings = numbers.map(num => String(num));
console.log(strings); // ['1', '2', '3', '4', '5']
// استخراج خصائص محددة من الكائنات
const users = [
{ name: 'احمد', age: 30 },
{ name: 'سارة', age: 25 },
{ name: 'خالد', age: 35 }
];
const names = users.map(user => user.name);
console.log(names); // ['احمد', 'سارة', 'خالد']
تحويل الكائنات باستخدام map
احد اكثر استخدامات map شيوعا في التطبيقات الحقيقية هو تحويل مصفوفات الكائنات. قد تستقبل بيانات من واجهة برمجة تطبيقات بتنسيق واحد وتحتاج لاعادة تشكيلها لمكونات واجهة المستخدم.
مثال: اعادة تشكيل بيانات API باستخدام map
// بيانات من واجهة برمجة تطبيقات
const apiResponse = [
{ id: 1, first_name: 'سارة', last_name: 'احمد', email_address: 'sara@example.com' },
{ id: 2, first_name: 'عمر', last_name: 'حسن', email_address: 'omar@example.com' },
{ id: 3, first_name: 'ليلى', last_name: 'محمد', email_address: 'layla@example.com' }
];
// التحويل الى التنسيق الذي تحتاجه واجهة المستخدم
const uiUsers = apiResponse.map(function(person) {
return {
userId: person.id,
fullName: person.first_name + ' ' + person.last_name,
email: person.email_address,
initials: person.first_name[0] + person.last_name[0]
};
});
console.log(uiUsers);
return داخل رد اتصال map. اذا نسيت ارجاع قيمة ستمتلئ المصفوفة الناتجة بقيم undefined. مع الدوال السهمية التي تستخدم الارجاع الضمني (بدون اقواس معقوفة) يكون الارجاع تلقائيا لكن مع جسم دالة (اقواس معقوفة) يجب كتابة return صراحة.دالة filter
تنشئ دالة filter مصفوفة جديدة تحتوي فقط على العناصر التي تجتاز اختبارا تنفذه الدالة المقدمة. يجب ان تعيد دالة رد الاتصال قيمة صحيحة او خاطئة لكل عنصر. العناصر التي يعيد فيها رد الاتصال قيمة صحيحة تضاف الى المصفوفة الجديدة والعناصر التي يعيد فيها قيمة خاطئة تستبعد. تبقى المصفوفة الاصلية دون تغيير.
التصفية الاساسية
مثال: اساسيات filter
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// الحصول على الارقام الزوجية فقط
const evens = numbers.filter(function(num) {
return num % 2 === 0;
});
console.log(evens); // [2, 4, 6, 8, 10]
// الارقام الاكبر من 5
const greaterThanFive = numbers.filter(num => num > 5);
console.log(greaterThanFive); // [6, 7, 8, 9, 10]
// تصفية النصوص حسب الطول
const words = ['قط', 'فيل', 'كلب', 'فرس النهر', 'نملة'];
const longWords = words.filter(word => word.length > 3);
console.log(longWords); // ['فرس النهر']
تصفية الكائنات
في التطبيقات الحقيقية ستقوم بتصفية مصفوفات الكائنات بشكل متكرر بناء على شرط واحد او اكثر. هذا شائع بشكل خاص في قوائم منتجات التجارة الالكترونية ونتائج البحث ولوحات المعلومات.
مثال: تصفية المنتجات
const products = [
{ name: 'لابتوب', price: 999, category: 'الكترونيات', inStock: true },
{ name: 'قميص', price: 29, category: 'ملابس', inStock: true },
{ name: 'سماعات', price: 199, category: 'الكترونيات', inStock: false },
{ name: 'كتاب', price: 15, category: 'كتب', inStock: true },
{ name: 'شاشة', price: 449, category: 'الكترونيات', inStock: true },
{ name: 'جينز', price: 59, category: 'ملابس', inStock: false }
];
// الحصول على الالكترونيات المتوفرة فقط
const availableElectronics = products.filter(function(product) {
return product.category === 'الكترونيات' && product.inStock;
});
console.log(availableElectronics);
// [{ name: 'لابتوب', ... }, { name: 'شاشة', ... }]
// المنتجات بسعر اقل من 50 والمتوفرة
const affordableAvailable = products.filter(function(product) {
return product.price < 50 && product.inStock;
});
console.log(affordableAvailable);
// [{ name: 'قميص', ... }, { name: 'كتاب', ... }]
filter ان تعيد مصفوفة فارغة اذا لم تتطابق اي عناصر مع الشرط. احرص دائما على مراعاة ذلك في كودك -- مثلا تحقق من طول المصفوفة المصفاة قبل محاولة الوصول الى عناصرها.دالة reduce
دالة reduce هي الاقوى والاكثر تنوعا بين جميع دوال تكرار المصفوفات. تنفذ دالة مخفض رد اتصال على كل عنصر في المصفوفة وتمرر القيمة المرجعة من تكرار الى التالي مما يؤدي في النهاية الى تقليص المصفوفة بالكامل الى قيمة متراكمة واحدة. يمكن ان تكون تلك القيمة رقما او نصا او كائنا او مصفوفة اخرى او اي نوع بيانات اخر.
الصيغة الاساسية
تاخذ دالة reduce معاملين: دالة رد اتصال مخفض وقيمة اولية اختيارية. يستقبل رد اتصال المخفض اربعة معاملات: المراكم (النتيجة المتراكمة من التكرارات السابقة) والعنصر الحالي والفهرس الحالي والمصفوفة المصدر. قدم دائما قيمة اولية لتجنب السلوك غير المتوقع مع المصفوفات الفارغة.
مثال: اساسيات reduce -- جمع الارقام
const numbers = [10, 20, 30, 40, 50];
// جمع كل الارقام
const total = numbers.reduce(function(accumulator, currentValue) {
return accumulator + currentValue;
}, 0);
console.log(total); // 150
// كيف تعمل خطوة بخطوة:
// الخطوة 1: المراكم = 0 (القيمة الاولية), الحالي = 10 => تعيد 10
// الخطوة 2: المراكم = 10, الحالي = 20 => تعيد 30
// الخطوة 3: المراكم = 30, الحالي = 30 => تعيد 60
// الخطوة 4: المراكم = 60, الحالي = 40 => تعيد 100
// الخطوة 5: المراكم = 100, الحالي = 50 => تعيد 150
// باستخدام الدالة السهمية
const sum = numbers.reduce((acc, num) => acc + num, 0);
استخدامات عملية لـ reduce
بعيدا عن الجمع البسيط يمكن لـ reduce بناء كائنات وتسطيح المصفوفات وعد التكرارات وايجاد القيم القصوى وتنفيذ اي عملية تراكم تقريبا.
مثال: اجمالي سلة التسوق باستخدام reduce
const cart = [
{ name: 'اداة', price: 25.99, quantity: 3 },
{ name: 'جهاز', price: 49.99, quantity: 1 },
{ name: 'ملحق', price: 9.99, quantity: 5 }
];
// حساب التكلفة الاجمالية
const cartTotal = cart.reduce(function(total, item) {
return total + (item.price * item.quantity);
}, 0);
console.log(cartTotal.toFixed(2)); // '177.91'
// عد اجمالي العناصر في السلة
const totalItems = cart.reduce(function(count, item) {
return count + item.quantity;
}, 0);
console.log(totalItems); // 9
مثال: عد التكرارات باستخدام reduce
const fruits = ['تفاح', 'موز', 'تفاح', 'كرز', 'موز', 'تفاح'];
const fruitCounts = fruits.reduce(function(counts, fruit) {
counts[fruit] = (counts[fruit] || 0) + 1;
return counts;
}, {});
console.log(fruitCounts);
// { تفاح: 3, موز: 2, كرز: 1 }
مثال: تجميع البيانات باستخدام reduce
const people = [
{ name: 'احمد', department: 'الهندسة' },
{ name: 'سارة', department: 'التسويق' },
{ name: 'خالد', department: 'الهندسة' },
{ name: 'نورة', department: 'التسويق' },
{ name: 'فاطمة', department: 'المبيعات' }
];
const grouped = people.reduce(function(groups, person) {
const dept = person.department;
if (!groups[dept]) {
groups[dept] = [];
}
groups[dept].push(person.name);
return groups;
}, {});
console.log(grouped);
// {
// الهندسة: ['احمد', 'خالد'],
// التسويق: ['سارة', 'نورة'],
// المبيعات: ['فاطمة']
// }
reduce. بدون قيمة اولية تستخدم reduce العنصر الاول من المصفوفة كمراكم اولي مما قد يسبب اخطاء مع المصفوفات الفارغة وسلوكا غير متوقع عند تقليص مصفوفات الكائنات. قدم دائما قيمة اولية صريحة.دوال find و findIndex
بينما تعيد filter جميع العناصر المطابقة احيانا تحتاج فقط اول عنصر يطابق شرطا. تعيد دالة find اول عنصر في المصفوفة يحقق دالة الاختبار المقدمة. اذا لم يطابق اي عنصر تعيد undefined. تعمل دالة findIndex بشكل مشابه لكنها تعيد فهرس اول عنصر مطابق او -1 اذا لم يوجد تطابق.
مثال: find و findIndex
const users = [
{ id: 1, name: 'احمد', role: 'مدير' },
{ id: 2, name: 'سارة', role: 'مستخدم' },
{ id: 3, name: 'خالد', role: 'مشرف' },
{ id: 4, name: 'نورة', role: 'مستخدم' }
];
// ايجاد اول مدير
const admin = users.find(function(user) {
return user.role === 'مدير';
});
console.log(admin); // { id: 1, name: 'احمد', role: 'مدير' }
// ايجاد مستخدم بالمعرف
const user = users.find(u => u.id === 3);
console.log(user.name); // 'خالد'
// ايجاد فهرس مستخدم محدد
const saraIndex = users.findIndex(u => u.name === 'سارة');
console.log(saraIndex); // 1
// عندما لا يوجد شيء
const superAdmin = users.find(u => u.role === 'مدير عام');
console.log(superAdmin); // undefined
const missingIndex = users.findIndex(u => u.name === 'زينب');
console.log(missingIndex); // -1
دوال some و every
تختبر دالة some ما اذا كان عنصر واحد على الاقل في المصفوفة يجتاز الاختبار المقدم. تعيد true بمجرد ان تجد عنصرا مطابقا وتتوقف عن التكرار. تختبر دالة every ما اذا كانت جميع العناصر تجتاز الاختبار. تعيد false بمجرد ان تجد عنصرا لا يطابق. كلا الدالتين تعيدان قيمة منطقية.
مثال: some و every
const scores = [85, 92, 78, 95, 88];
// هل حصل احد على اكثر من 90؟
const hasHighScore = scores.some(score => score > 90);
console.log(hasHighScore); // true
// هل نجح الجميع (اكثر من 70)؟
const allPassed = scores.every(score => score > 70);
console.log(allPassed); // true
// هل حصل الجميع على اكثر من 80؟
const allAbove80 = scores.every(score => score > 80);
console.log(allAbove80); // false (78 لم ينجح)
// مثال عملي: التحقق من النموذج
const formFields = [
{ name: 'email', value: 'user@example.com', valid: true },
{ name: 'password', value: 'secret123', valid: true },
{ name: 'age', value: '', valid: false }
];
const isFormValid = formFields.every(field => field.valid);
console.log(isFormValid); // false
const hasAnyInput = formFields.some(field => field.value.length > 0);
console.log(hasAnyInput); // true
some و every تستخدمان تقييم الدائرة القصيرة. تتوقف some بمجرد ايجاد نتيجة true وتتوقف every بمجرد ايجاد نتيجة false. هذا يجعلهما اكثر كفاءة من التكرار على المصفوفة بالكامل عندما يكون الجواب المبكر ممكنا.ربط دوال المصفوفات
احدى اعظم نقاط قوة دوال المصفوفات هذه انه يمكن ربطها معا. بما ان map و filter تعيدان مصفوفات جديدة يمكنك استدعاء دالة مصفوفة اخرى مباشرة على النتيجة. يتيح لك هذا بناء خطوط انابيب معالجة بيانات معقدة تكون قوية وقابلة للقراءة في ان واحد.
مثال: ربط filter و map و reduce
const orders = [
{ product: 'لابتوب', amount: 999, status: 'مكتمل' },
{ product: 'ماوس', amount: 29, status: 'مكتمل' },
{ product: 'لوحة مفاتيح', amount: 79, status: 'ملغي' },
{ product: 'شاشة', amount: 449, status: 'مكتمل' },
{ product: 'كاميرا ويب', amount: 89, status: 'قيد الانتظار' },
{ product: 'مكتب', amount: 299, status: 'مكتمل' }
];
// حساب اجمالي الايرادات من الطلبات المكتملة
const totalRevenue = orders
.filter(order => order.status === 'مكتمل')
.reduce((sum, order) => sum + order.amount, 0);
console.log(totalRevenue); // 1776
// الحصول على اسماء الطلبات المكتملة فوق 100 دولار منسقة
const bigCompletedOrders = orders
.filter(order => order.status === 'مكتمل')
.filter(order => order.amount > 100)
.map(order => order.product + ' ($' + order.amount + ')');
console.log(bigCompletedOrders);
// ['لابتوب ($999)', 'شاشة ($449)', 'مكتب ($299)']
مثال: خط انابيب بيانات معقد
const employees = [
{ name: 'احمد', department: 'الهندسة', salary: 95000, active: true },
{ name: 'سارة', department: 'التسويق', salary: 72000, active: true },
{ name: 'خالد', department: 'الهندسة', salary: 88000, active: false },
{ name: 'نورة', department: 'الهندسة', salary: 102000, active: true },
{ name: 'فاطمة', department: 'التسويق', salary: 68000, active: true },
{ name: 'عمر', department: 'المبيعات', salary: 78000, active: true }
];
// الحصول على متوسط راتب مهندسي الهندسة النشطين
const activeEngineers = employees
.filter(emp => emp.active && emp.department === 'الهندسة');
const avgSalary = activeEngineers
.reduce((sum, emp) => sum + emp.salary, 0) / activeEngineers.length;
console.log(avgSalary); // 98500
// انشاء ملخص الاقسام
const departmentSummary = employees
.filter(emp => emp.active)
.reduce(function(summary, emp) {
if (!summary[emp.department]) {
summary[emp.department] = { count: 0, totalSalary: 0 };
}
summary[emp.department].count += 1;
summary[emp.department].totalSalary += emp.salary;
return summary;
}, {});
console.log(departmentSummary);
اعتبارات الاداء
بينما دوال تكرار المصفوفات انيقة وقابلة للقراءة من المهم فهم خصائص ادائها خاصة عند العمل مع مجموعات بيانات كبيرة.
- الربط ينشئ مصفوفات وسيطة -- عندما تربط
filter().map()تنشئ دالةfilterمصفوفة مؤقتة ثم تكررmapعليها. للمصفوفات الكبيرة جدا (مئات الالاف من العناصر) قد يستهلك هذا ذاكرة اضافية. في مثل هذه الحالات فكر في استخدامreduceواحد لتنفيذ العمليتين في تمريرة واحدة. - forEach مقابل حلقة for -- حلقة
forالتقليدية اسرع قليلا منforEachلانها تتجنب عبء استدعاءات الدوال. لكن الفرق لا يذكر لمعظم التطبيقات. اعط الاولوية للقراءة الا اذا كنت تتعامل مع كود حرج الاداء يعالج ملايين العناصر. - الانهاء المبكر -- دوال مثل
findوfindIndexوsomeوeveryتتوقف عن التكرار بمجرد تحديد النتيجة. استخدمها بدلا منfilterعندما تحتاج فقط التطابق الاول او اجابة منطقية. - تجنب التعديلات -- لا تعدل ابدا المصفوفة الاصلية داخل رد اتصال
mapاوfilterاوforEach. هذا يؤدي الى اخطاء غير متوقعة. عامل دائما المصفوفة المصدر كقابلة للقراءة فقط وابن هياكل بيانات جديدة بدلا من ذلك.
مثال: التحسين باستخدام reduce واحد بدلا من الربط
const data = [
{ value: 10, active: true },
{ value: 20, active: false },
{ value: 30, active: true },
{ value: 40, active: true },
{ value: 50, active: false }
];
// اقل كفاءة: تمريرتان على البيانات
const result1 = data
.filter(item => item.active)
.map(item => item.value * 2);
// اكثر كفاءة: تمريرة واحدة
const result2 = data.reduce(function(acc, item) {
if (item.active) {
acc.push(item.value * 2);
}
return acc;
}, []);
// كلاهما ينتج [20, 60, 80]
امثلة واقعية لمعالجة البيانات
دعنا نجمع كل شيء معا بامثلة شاملة تعكس سيناريوهات حقيقية ستواجهها في تطوير JavaScript المهني.
مثال: تصفية وعرض منتجات التجارة الالكترونية
const products = [
{ id: 1, name: 'ماوس لاسلكي', price: 29.99, rating: 4.5, category: 'اكسسوارات', inStock: true },
{ id: 2, name: 'لوحة مفاتيح ميكانيكية', price: 89.99, rating: 4.8, category: 'اكسسوارات', inStock: true },
{ id: 3, name: 'موزع USB', price: 19.99, rating: 3.9, category: 'اكسسوارات', inStock: false },
{ id: 4, name: 'حامل لابتوب', price: 45.99, rating: 4.2, category: 'اثاث', inStock: true },
{ id: 5, name: 'اضاءة شاشة', price: 59.99, rating: 4.7, category: 'اضاءة', inStock: true },
{ id: 6, name: 'لوحة مكتب', price: 24.99, rating: 4.1, category: 'اكسسوارات', inStock: true }
];
// 1. الحصول على الاكسسوارات المتوفرة مرتبة حسب التقييم
const topAccessories = products
.filter(p => p.category === 'اكسسوارات' && p.inStock)
.sort((a, b) => b.rating - a.rating)
.map(p => p.name + ' - $' + p.price + ' (تقييم: ' + p.rating + ')');
console.log(topAccessories);
// 2. حساب متوسط سعر المنتجات المتوفرة
const inStockProducts = products.filter(p => p.inStock);
const avgPrice = inStockProducts
.reduce((sum, p) => sum + p.price, 0) / inStockProducts.length;
console.log('متوسط السعر: $' + avgPrice.toFixed(2));
// 3. التحقق مما اذا كان اي منتج يحتاج اعادة تخزين
const needsRestock = products.some(p => !p.inStock);
console.log('يحتاج اعادة تخزين:', needsRestock); // true
// 4. تجميع المنتجات حسب الفئة مع الاحصائيات
const categoryStats = products.reduce(function(stats, product) {
const cat = product.category;
if (!stats[cat]) {
stats[cat] = { total: 0, inStock: 0, avgRating: 0, ratings: [] };
}
stats[cat].total += 1;
if (product.inStock) stats[cat].inStock += 1;
stats[cat].ratings.push(product.rating);
return stats;
}, {});
// حساب متوسط التقييمات لكل فئة
Object.keys(categoryStats).forEach(function(cat) {
const ratings = categoryStats[cat].ratings;
categoryStats[cat].avgRating = ratings.reduce((s, r) => s + r, 0) / ratings.length;
delete categoryStats[cat].ratings;
});
console.log(categoryStats);
مثال: تحويل بيانات استجابة API
// استجابة API محاكاة
const apiData = {
status: 'success',
results: [
{ user_id: 101, first_name: 'احمد', last_name: 'حسن',
email: 'ahmad@example.com', created_at: '2024-01-15', orders_count: 12 },
{ user_id: 102, first_name: 'سارة', last_name: 'علي',
email: 'sara@example.com', created_at: '2024-03-22', orders_count: 0 },
{ user_id: 103, first_name: 'عمر', last_name: 'خان',
email: 'omar@example.com', created_at: '2023-11-08', orders_count: 45 },
{ user_id: 104, first_name: 'ليلى', last_name: 'محمود',
email: 'layla@example.com', created_at: '2024-06-01', orders_count: 7 }
]
};
// التحويل الى تنسيق صديق لواجهة المستخدم للعملاء النشطين فقط
const activeCustomers = apiData.results
.filter(user => user.orders_count > 0)
.map(function(user) {
return {
id: user.user_id,
displayName: user.first_name + ' ' + user.last_name,
email: user.email,
memberSince: new Date(user.created_at).toLocaleDateString(),
isVIP: user.orders_count > 10,
tier: user.orders_count > 20 ? 'ذهبي' : user.orders_count > 10 ? 'فضي' : 'برونزي'
};
});
console.log(activeCustomers);
// احصائيات ملخصة
const stats = apiData.results.reduce(function(acc, user) {
acc.totalOrders += user.orders_count;
acc.activeUsers += user.orders_count > 0 ? 1 : 0;
return acc;
}, { totalOrders: 0, activeUsers: 0 });
console.log('اجمالي الطلبات: ' + stats.totalOrders); // 64
console.log('المستخدمون النشطون: ' + stats.activeUsers); // 3
تمرين عملي
انشئ مصفوفة من 8 كائنات طلاب على الاقل كل منها بخصائص name و grade (رقم من 0-100) و subject (واحد من 'رياضيات' او 'علوم' او 'انجليزي') و enrolled (قيمة منطقية). ثم اكمل هذه المهام باستخدام دوال تكرار المصفوفات:
- استخدم
filterللحصول على جميع الطلاب المسجلين بدرجة اعلى من 75. - استخدم
mapلانشاء مصفوفة نصوص بالتنسيق "الاسم: الدرجة% (المادة)". - استخدم
reduceلحساب متوسط الدرجات عبر جميع الطلاب المسجلين. - استخدم
findلايجاد اول طالب في مادة الرياضيات باعلى درجة. - استخدم
someللتحقق مما اذا كان اي طالب راسبا (درجة اقل من 50). - استخدم
everyللتحقق مما اذا كان جميع الطلاب المسجلين لديهم درجة اعلى من 30. - اربط
filterوreduceلايجاد اجمالي نقاط الدرجات لطلاب العلوم المسجلين. - استخدم
reduceلتجميع الطلاب حسب المادة وعد كم طالب مسجل في كل منها.