Array.prototype.reduce()
الدالة Array.prototype.reduce()
تؤدي إلى اختزال جميع قيم المصفوفة (بدءًا من اليسار إلى اليمين) إلى قيمة واحدة.
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer)); // 10
// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5)); // 15
البنية العامة
arr.reduce(callback[, initialValue])
callback
الدالة التي ستختبر كل عنصر من عناصر المصفوفة، وتقبل أربعة وسائط.
accumulator
القيمة التراكمية، انظر النقاش أدناه للتفاصيل.
currentValue
العنصر الحالي الذي يُعالِج في المصفوفة، وهذه القيمة مطلوبة.
currentIndex
فهرس العنصر الحالي في المصفوفة، وهذه القيمة اختيارية.
array
المصفوفة التي استدعيت الدالة reduce
عليها، وهذه القيمة اختيارية.
initialValue
القيمة التي ستُستخدم كوسيط لأوّل استدعاء للدالة callback
، وإن لم توفَّر هذه القيمة فسيستخدم أوّل عنصر في المصفوفة.
القيمة المعادة
القيمة الناتجة من عملية الاختزال.
الوصف
الدالة reduce
تستدعي الدالة callback
مرةً واحدةً لكل عنصر في المصفوفة، باستثناء الفجوات الموجودة في المصفوفة، وهذه الدالة تقبل أربعة وسائط:
accumulator
currentValue
currentIndex
array
في أوّل استدعاء للدالة callback
، تكون accumulator
و currentValue
قيمةً من قيمتين. فإذا وفّرنا قيمةً للوسيط initialValue
عند استدعاء reduce
فستكون accumulator
مساويةً إلى initialValue
، وستكون currentValue
مساويةً إلى أوّل عنصر في المصفوفة؛ أما إذا لم تكن قيمة الوسيط initialValue
موجودةً، فستكون accumulator
مساويةً لأوّل قيمة في المصفوفة، و currentValue
ستساوي القيمة الثانية.
ملاحظة: إذا لم توفَّر قيمة initialValue
فستُنفِّذ الدالةُ reduce
الدالةَ callback
بدءًا من الفهرس 1 وستتجاوز أوّل فهرس، أما إذا كانت القيمة initialValue
موجودةً فستبدأ من الفهرس 0.
إذا كانت المصفوفة فارغة ولم توفَّر قيمة initialValue
، فسيرمى الاستثناء TypeError
، وإذا احتوت المصفوفة على عنصرٍ وحيد (بغض النظر عن موضعه) ولم توفَّر قيمة initialValue
أو كانت القيمة initialValue
موجودةً لكن المصفوفة فارغة، فستُعاد القيمة الوحيدة دون استدعاء الدالة callback
.
من الأفضل توفير قيمة ابتدائية دومًا لأنَّ هنالك ثلاث حالات يمكن أن تحدث إن لم تكن قيمة initialValue
مضبوطةً، كما هو موضَّح في المثال الآتي:
var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );
var maxCallback2 = ( max, cur ) => Math.max( max, cur );
// دون قيمة ابتدائية
[ { x: 22 }, { x: 42 } ].reduce( maxCallback ); // 42
[ { x: 22 } ].reduce( maxCallback ); // { x: 22 }
[ ].reduce( maxCallback ); // TypeError
// مع قيمة ابتدائية
[ { x: 22 }, { x: 42 } ].map( el => el.x )
.reduce( maxCallback2, -Infinity );
كيف تعمل الدالة reduce
لنفترض أنَّ لدينا المثال الآتي:
[0, 1, 2, 3, 4].reduce(
function (
accumulator,
currentValue,
currentIndex,
array
) {
return accumulator + currentValue;
}
);
ستُستدعى الدالة callback
أربع مرات، وسنستعرض الوسائط الممررة إليها والقيم التي تعيدها في الجدول الآتي:
callback | accumulator | currentValue | currentIndex | array | القيمة المعادة |
---|---|---|---|---|---|
أوّل استدعاء | 0
|
1
|
1
|
[0, 1, 2, 3, 4]
|
1
|
ثاني استدعاء | 1
|
2
|
2
|
[0, 1, 2, 3, 4]
|
3
|
ثالث استدعاء | 3
|
3
|
3
|
[0, 1, 2, 3, 4]
|
6
|
رابع استدعاء | 6
|
4
|
4
|
[0, 1, 2, 3, 4]
|
10
|
القيمة المعادة من الدالة reduce
هي آخر قيمة مُعادة من الدالة callback
(وهي 10
).
يمكنك أيضًا استخدام الدوال السهمية بدلًا من استخدام دالة كاملة، فالمثال السابق يُنتِج نفس النتيجة السابقة:
[0, 1, 2, 3, 4].reduce( (prev, curr) => prev + curr );
أما إذا وفّرتَ قيمةً ابتدائيةً كوسيطٍ ثانٍ للدالة reduce
، أي أنَّ الشيفرة كالآتية:
[0, 1, 2, 3, 4].reduce(
(accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue;
},
10
);
والجدول:
callback | accumulator | currentValue | currentIndex | array | القيمة المعادة |
---|---|---|---|---|---|
أوّل استدعاء | 10
|
0
|
0
|
[0, 1, 2, 3, 4]
|
10
|
ثاني استدعاء | 10
|
1
|
1
|
[0, 1, 2, 3, 4]
|
11
|
ثالث استدعاء | 11
|
2
|
2
|
[0, 1, 2, 3, 4]
|
13
|
رابع استدعاء | 16
|
4
|
4
|
[0, 1, 2, 3, 4]
|
20
|
القيمة المعادة من الدالة reduce
في هذه الحالة هي 20.
أمثلة
جمع كل القيم في المصفوفة
var sum = [0, 1, 2, 3].reduce(function (a, b) {
return a + b;
}, 0);
// 6
يمكن كتابة الشيفرة السابقة باستخدام دالة سهمية:
var total = [ 0, 1, 2, 3 ].reduce(
( acc, cur ) => acc + cur,
0
);
تسطيح مصفوفة من المصفوفات
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
function(a, b) {
return a.concat(b);
},
[]
);
// [0, 1, 2, 3, 4, 5]
يمكن كتابة الشيفرة السابقة باستخدام دالة سهمية:
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
( acc, cur ) => acc.concat(cur),
[]
);
إحصاء عدد تكرار عناصر المصفوفة
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
var countedNames = names.reduce(function (allNames, name) {
if (name in allNames) {
allNames[name]++;
}
else {
allNames[name] = 1;
}
return allNames;
}, {});
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
تعويض نقص دعم المتصفحات
أضيفت هذه الدالة في الإصدار الخامس من معيار ECMAScript، لذا يمكنك استخدام الشيفرة الآتية لإضافتها للمتصفحات التي لا تدعمها:
// Production steps of ECMA-262, Edition 5, 15.4.4.21
// Reference: http://es5.github.io/#x15.4.4.21
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
if (!Array.prototype.reduce) {
Object.defineProperty(Array.prototype, 'reduce', {
value: function(callback /*, initialValue*/) {
if (this === null) {
throw new TypeError( 'Array.prototype.reduce ' +
'called on null or undefined' );
}
if (typeof callback !== 'function') {
throw new TypeError( callback +
' is not a function');
}
// 1. Let O be ? ToObject(this value).
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// Steps 3, 4, 5, 6, 7
var k = 0;
var value;
if (arguments.length >= 2) {
value = arguments[1];
} else {
while (k < len && !(k in o)) {
k++;
}
// 3. If len is 0 and initialValue is not present,
// throw a TypeError exception.
if (k >= len) {
throw new TypeError( 'Reduce of empty array ' +
'with no initial value' );
}
value = o[k++];
}
// 8. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kPresent be ? HasProperty(O, Pk).
// c. If kPresent is true, then
// i. Let kValue be ? Get(O, Pk).
// ii. Let accumulator be ? Call(
// callbackfn, undefined,
// « accumulator, kValue, k, O »).
if (k in o) {
value = callback(value, o[k], k, o);
}
// d. Increase k by 1.
k++;
}
// 9. Return accumulator.
return value;
}
});
}
دعم المتصفحات
الميزة | Chrome | Firefox | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
الدعم الأساسي | نعم | نعم | 9 | نعم | 4 |
مصادر ومواصفات
- مسودة المعيار ECMAScript Latest Draft.
- معيار ECMAScript 2015 (6th Edition).
- معيار ECMAScript 5.1.