توفر المصفوفات الكثير من الأساليب. ولتسهيل الأمور، تم تقسيمهم في هذا الفصل إلى مجموعات.
نحن نعرف بالفعل الطرق التي تضيف وتزيل العناصر من البداية أو النهاية:
arr.push(...items)
- يضيف العناصر إلى النهاية،
arr.pop()
– يستخرج عنصرًا من النهاية،
arr.shift()
– يستخرج العنصر من البداية،
arr.unshift(...items)
- يضيف العناصر إلى البداية.
وهنا عدد قليل من الآخرين.
كيفية حذف عنصر من المصفوفة؟
المصفوفات عبارة عن كائنات، لذا يمكننا محاولة استخدام delete
:
Let arr = ["I"، "go"، "home"]؛ حذف آر [1]؛ // إزالة "اذهب" تنبيه(ar[1]); // غير محدد // الآن arr = ["I"، , "home"]; تنبيه (arr.length)؛ // 3
تمت إزالة العنصر، لكن المصفوفة لا تزال تحتوي على 3 عناصر، يمكننا أن نرى أن arr.length == 3
.
وهذا أمر طبيعي، لأن delete obj.key
يزيل القيمة بواسطة key
. هذا كل ما يفعله. غرامة للكائنات. لكن بالنسبة للمصفوفات، نريد عادةً أن تتحرك بقية العناصر وتحتل المكان الحر. نتوقع أن يكون لدينا مجموعة أقصر الآن.
لذلك، ينبغي استخدام أساليب خاصة.
طريقة arr.splice هي سكين الجيش السويسري للمصفوفات. يمكنه فعل كل شيء: إدراج العناصر وإزالتها واستبدالها.
بناء الجملة هو:
arr.splice(start[,deleteCount,elem1,...,elemN])
يقوم بتعديل arr
بدءًا من start
الفهرس: يزيل عناصر deleteCount
ثم يقوم بإدراج elem1, ..., elemN
في مكانها. إرجاع مصفوفة العناصر التي تمت إزالتها.
هذه الطريقة سهلة الفهم من خلال الأمثلة.
لنبدأ بالحذف:
Let arr = ["I"، "study"، "JavaScript"]؛ arr.splice(1, 1); // من الفهرس 1 قم بإزالة عنصر واحد تنبيه(آر); // ["أنا"، "جافا سكريبت"]
سهل، أليس كذلك؟ بدءًا من الفهرس 1
، تمت إزالة عنصر 1
.
في المثال التالي، نقوم بإزالة 3 عناصر واستبدالها بالعنصرين الآخرين:
Let arr = ["I"، "study"، "JavaScript"، "right"، "now"]; // إزالة العناصر الثلاثة الأولى واستبدالها بأخرى arr.splice(0, 3, "دعونا"، "الرقص")؛ تنبيه ( arr ) // الآن ["دعونا"، "الرقص"، "صحيح"، "الآن"]
هنا يمكننا أن نرى أن splice
تُرجع مصفوفة العناصر المُزالة:
Let arr = ["I"، "study"، "JavaScript"، "right"، "now"]; // إزالة العنصرين الأولين دع إزالة = arr.splice(0, 2); تنبيه (تمت الإزالة) ؛ // "I"، "study" <-- مجموعة من العناصر المحذوفة
طريقة splice
قادرة أيضًا على إدراج العناصر دون أي عمليات إزالة. للقيام بذلك، نحن بحاجة إلى تعيين deleteCount
إلى 0
:
Let arr = ["I"، "study"، "JavaScript"]؛ // من الفهرس 2 // حذف 0 // ثم أدخل "معقد" و"لغة" arr.splice(2, 0, "complex", "language"); تنبيه(آر); // "أنا"، "دراسة"، "معقدة"، "لغة"، "جافا سكريبت"
الفهارس السلبية مسموح بها
هنا وفي طرق المصفوفة الأخرى، يُسمح بالفهارس السالبة. وهي تحدد الموضع من نهاية المصفوفة، كما هو الحال هنا:
دع arr = [1, 2, 5]; // من الفهرس -1 (خطوة واحدة من النهاية) // حذف 0 عنصر، // ثم أدخل 3 و 4 arr.splice(-1, 0, 3, 4); تنبيه(آر); // 1,2,3,4,5
الطريقة arr.slice أبسط بكثير من الطريقة arr.splice
المشابهة لها.
بناء الجملة هو:
arr.slice([البداية]، [النهاية])
تقوم بإرجاع مصفوفة جديدة تنسخ إليها جميع العناصر من start
الفهرس إلى end
(لا يشمل end
). يمكن أن تكون كل من start
end
سالبة، وفي هذه الحالة يُفترض الموضع من نهاية المصفوفة.
إنه مشابه لطريقة السلسلة str.slice
، ولكن بدلاً من السلاسل الفرعية، فإنه يقوم بإنشاء مصفوفات فرعية.
على سبيل المثال:
Let arr = ["t"، "e"، "s"، "t"]؛ تنبيه(arr.slice(1, 3)); // e,s (نسخ من 1 إلى 3) تنبيه(arr.slice(-2)); // s,t (انسخ من -2 حتى النهاية)
يمكننا أيضًا تسميتها بدون وسيطات: ينشئ arr.slice()
نسخة من arr
. يُستخدم هذا غالبًا للحصول على نسخة لمزيد من التحويلات التي لا ينبغي أن تؤثر على المصفوفة الأصلية.
ينشئ الأسلوب arr.concat مصفوفة جديدة تتضمن قيمًا من مصفوفات أخرى وعناصر إضافية.
بناء الجملة هو:
arr.concat(arg1, arg2...)
يقبل أي عدد من الوسائط – سواء المصفوفات أو القيم.
والنتيجة هي مصفوفة جديدة تحتوي على عناصر من arr
ثم arg1
و arg2
وما إلى ذلك.
إذا كانت الوسيطة argN
عبارة عن مصفوفة، فسيتم نسخ جميع عناصرها. وإلا، فسيتم نسخ الوسيطة نفسها.
على سبيل المثال:
دع آر = [1، 2]؛ // إنشاء مصفوفة من: arr و[3,4] تنبيه( arr.concat([3, 4])); // 1,2,3,4 // أنشئ مصفوفة من: arr و[3,4] و[5,6] تنبيه( arr.concat([3, 4], [5, 6])); // 1,2,3,4,5,6 // أنشئ مصفوفة من: arr و[3,4]، ثم أضف القيمتين 5 و6 تنبيه( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6
عادةً ما يقوم بنسخ العناصر من المصفوفات فقط. يتم إضافة كائنات أخرى، حتى لو كانت تبدو مثل المصفوفات، ككل:
دع آر = [1، 2]؛ دع المصفوفة مثل = { 0: "شيء"، الطول: 1 }; تنبيه( arr.concat(arrayLike)); // 1،2،[كائن كائن]
…ولكن إذا كان كائن يشبه المصفوفة يحتوي على خاصية Symbol.isConcatSpreadable
خاصة، فسيتم التعامل معه كمصفوفة بواسطة concat
: تتم إضافة عناصره بدلاً من ذلك:
دع آر = [1، 2]؛ دع المصفوفة مثل = { 0: "شيء"، 1: "آخر"، [Symbol.isConcatSpreadable]: صحيح، الطول: 2 }; تنبيه( arr.concat(arrayLike)); // 1،2، شيء ما، آخر
يسمح التابع arr.forEach بتشغيل دالة لكل عنصر في المصفوفة.
بناء الجملة:
arr.forEach(function(item, Index, array) { // ... افعل شيئًا بعنصر ما });
على سبيل المثال، يظهر هذا كل عنصر من عناصر المصفوفة:
// تنبيه استدعاء لكل عنصر ["بيلبو"، "جاندالف"، "نازجول"].forEach(alert);
وهذا الكود أكثر تفصيلاً حول مواقعهم في المصفوفة المستهدفة:
["Bilbo"، "Gandalf"، "Nazgul"].forEach((item, Index, array) => { تنبيه(`${item} موجود في الفهرس ${index} في ${array}`); });
يتم التخلص من نتيجة الدالة (في حالة إرجاعها) وتجاهلها.
الآن دعونا نغطي الطرق التي تبحث في مصفوفة.
التابعان arr.indexOf وarr.includes لهما بناء جملة مماثل ويفعلان نفس عمل نظيراتهما من السلسلة، لكنهما يعملان على العناصر بدلاً من الأحرف:
arr.indexOf(item, from)
- يبحث عن item
الذي يبدأ من الفهرس from
، ويعيد الفهرس الذي تم العثور عليه فيه، وإلا -1
.
arr.includes(item, from)
- يبحث عن item
بدءًا من الفهرس from
، ويُرجع true
إذا تم العثور عليه.
عادة، يتم استخدام هذه الأساليب مع وسيطة واحدة فقط: item
المطلوب البحث عنه. بشكل افتراضي، يكون البحث من البداية.
على سبيل المثال:
دع arr = [1, 0, false]; تنبيه(arr.indexOf(0)); // 1 تنبيه( arr.indexOf(خطأ)); // 2 تنبيه( arr.indexOf(null)); // -1 تنبيه(ar.includes(1)); // حقيقي
يرجى ملاحظة أن indexOf
يستخدم المساواة الصارمة ===
للمقارنة. لذا، إذا بحثنا عن false
، فستجده false
تمامًا وليس الصفر.
إذا أردنا التحقق مما إذا كان item
موجودًا في المصفوفة ولا يحتاج إلى الفهرس، فمن الأفضل استخدام arr.includes
.
الطريقة arr.lastIndexOf هي نفس طريقة indexOf
، ولكنها تبحث من اليمين إلى اليسار.
دع الفواكه = ['Apple'، 'Orange'، 'Apple'] تنبيه(fruits.indexOf('Apple')); // 0 (أبل الأولى) تنبيه(fruits.lastIndexOf('Apple')); // 2 (أبل الأخيرة)
الأسلوب includes
يعالج NaN
بشكل صحيح
إحدى ميزات includes
البسيطة، ولكن الجديرة بالملاحظة، هي أنها تتعامل بشكل صحيح مع NaN
، على عكس indexOf
:
const arr = [NaN]; تنبيه( arr.indexOf(NaN) ); // -1 (خطأ، يجب أن يكون 0) تنبيه (arr.includes(NaN))؛// صحيح (صحيح)
وذلك لأنه تمت إضافة includes
إلى JavaScript في وقت لاحق ويستخدم خوارزمية مقارنة أكثر حداثة داخليًا.
تخيل أن لدينا مجموعة من الكائنات. كيف يمكننا العثور على كائن مع حالة معينة؟
هنا تكون طريقة arr.find(fn) مفيدة.
بناء الجملة هو:
دع النتيجة = arr.find(function(item, Index, array) { // إذا تم إرجاع صحيح، فسيتم إرجاع العنصر وإيقاف التكرار // للسيناريو الخاطئ يُرجع غير محدد });
يتم استدعاء الدالة لعناصر المصفوفة، واحدة تلو الأخرى:
item
هو العنصر
index
هو فهرسه.
array
هي المصفوفة نفسها
إذا عادت القيمة true
، فسيتم إيقاف البحث، ويتم إرجاع item
. إذا لم يتم العثور على شيء، فسيتم إرجاع undefined
.
على سبيل المثال، لدينا مجموعة من المستخدمين، لكل منهم الحقلان id
و name
. دعونا نجد واحد مع id == 1
:
السماح للمستخدمين = [ {المعرف: 1، الاسم: "جون"}، {المعرف: 2، الاسم: "بيت"}، {المعرف: 3، الاسم: "مريم"} ]; السماح للمستخدم = users.find(item => item.id == 1); تنبيه (اسم المستخدم) ؛ // جون
في الحياة الواقعية، تعد مصفوفات الكائنات أمرًا شائعًا، لذا فإن طريقة find
مفيدة جدًا.
لاحظ أنه في المثال الذي نقدمه يمكنك find
item => item.id == 1
باستخدام وسيطة واحدة. هذا أمر نموذجي، ونادرا ما يتم استخدام الوسائط الأخرى لهذه الوظيفة.
يحتوي الأسلوب arr.findIndex على نفس البنية ولكنه يُرجع الفهرس الذي تم العثور على العنصر فيه بدلاً من العنصر نفسه. يتم إرجاع قيمة -1
إذا لم يتم العثور على شيء.
التابع arr.findLastIndex يشبه findIndex
، لكنه يبحث من اليمين إلى اليسار، تمامًا مثل lastIndexOf
.
هنا مثال:
السماح للمستخدمين = [ {المعرف: 1، الاسم: "جون"}، {المعرف: 2، الاسم: "بيت"}، {المعرف: 3، الاسم: "مريم"}، {المعرف: 4، الاسم: "جون"} ]; // ابحث عن فهرس يوحنا الأول تنبيه(users.findIndex(user => user.name == 'John')); // 0 // ابحث عن فهرس يوحنا الأخير تنبيه(users.findLastIndex(user => user.name == 'John')); // 3
تبحث طريقة find
عن عنصر واحد (أول) يجعل الدالة ترجع true
.
إذا كان هناك الكثير، فيمكننا استخدام arr.filter(fn).
بناء الجملة مشابه لـ find
، لكن filter
يُرجع مصفوفة من جميع العناصر المطابقة:
دع النتائج = arr.filter(function(item, Index, array) { // إذا تم دفع العنصر الحقيقي إلى النتائج واستمر التكرار // يُرجع مصفوفة فارغة إذا لم يتم العثور على أي شيء });
على سبيل المثال:
السماح للمستخدمين = [ {المعرف: 1، الاسم: "جون"}، {المعرف: 2، الاسم: "بيت"}، {المعرف: 3، الاسم: "مريم"} ]; // يُرجع مصفوفة من أول مستخدمين Let someUsers = users.filter(item => item.id < 3); تنبيه (بعض المستخدمين. الطول)؛ // 2
دعنا ننتقل إلى الأساليب التي تحول وتعيد ترتيب المصفوفة.
تعد طريقة arr.map واحدة من أكثر الطرق فائدةً وأكثرها استخدامًا.
فهو يستدعي الدالة لكل عنصر من عناصر المصفوفة ويعيد مصفوفة النتائج.
بناء الجملة هو:
دع النتيجة = arr.map(function(item, Index, array) { // يُرجع القيمة الجديدة بدلاً من العنصر });
على سبيل المثال، نقوم هنا بتحويل كل عنصر إلى طوله:
Let lengths = ["Bilbo"، "Gandalf"، "Nazgul"].map(item => item.length); تنبيه (أطوال)؛ // 5,7,6
يؤدي استدعاء الدالة arr.sort() إلى فرز المصفوفة في مكانها ، وتغيير ترتيب عناصرها.
كما تقوم أيضًا بإرجاع المصفوفة التي تم فرزها، ولكن عادةً ما يتم تجاهل القيمة التي يتم إرجاعها، حيث يتم تعديل arr
نفسه.
على سبيل المثال:
دع arr = [ 1, 2, 15 ]; // تعيد الطريقة ترتيب محتوى arr arr.sort(); تنبيه(آر); // 1، 15، 2
هل لاحظتم أي شيء غريب في النتيجة؟
أصبح الترتيب 1, 15, 2
. غير صحيح. لكن لماذا؟
يتم فرز العناصر كسلاسل بشكل افتراضي.
حرفيًا، يتم تحويل جميع العناصر إلى سلاسل لإجراء المقارنات. بالنسبة للسلاسل، يتم تطبيق الترتيب المعجمي وبالفعل "2" > "15"
.
لاستخدام ترتيب الفرز الخاص بنا، نحتاج إلى توفير دالة كوسيط للدالة arr.sort()
.
يجب أن تقارن الدالة قيمتين عشوائيتين وترجع:
مقارنة الدالة (أ، ب) { إذا (أ > ب) يعود 1؛ // إذا كانت القيمة الأولى أكبر من الثانية إذا (أ == ب) أرجع 0؛ // إذا كانت القيم متساوية إذا (أ < ب) العودة -1؛ // إذا كانت القيمة الأولى أقل من الثانية }
على سبيل المثال، للفرز كأرقام:
وظيفة المقارنة الرقمية (أ، ب) { إذا (أ > ب) يعود 1؛ إذا (أ == ب) أرجع 0؛ إذا (أ < ب) العودة -1؛ } دع arr = [ 1, 2, 15 ]; arr.sort(compareNumeric); تنبيه(arr); // 1، 2، 15
الآن يعمل على النحو المنشود.
دعونا نتنحى جانبا ونفكر في ما يحدث. يمكن أن يكون arr
مجموعة من أي شيء، أليس كذلك؟ قد تحتوي على أرقام أو سلاسل أو كائنات أو أي شيء. لدينا مجموعة من بعض العناصر . لفرزها، نحتاج إلى دالة ترتيب تعرف كيفية مقارنة عناصرها. الافتراضي هو ترتيب السلسلة.
تطبق طريقة arr.sort(fn)
خوارزمية فرز عامة. لا نحتاج إلى الاهتمام بكيفية عمله داخليًا (الفرز السريع المحسّن أو Timsort في معظم الأوقات). سوف يتنقل في المصفوفة، ويقارن عناصرها باستخدام الوظيفة المتوفرة ويعيد ترتيبها، كل ما نحتاجه هو توفير fn
الذي يقوم بإجراء المقارنة.
بالمناسبة، إذا أردنا معرفة العناصر التي تمت مقارنتها، فلا شيء يمنعنا من تنبيهها:
[1، -2، 15، 2، 0، 8].sort(function(a, b) { تنبيه(أ + " <> " + ب ); العودة أ - ب؛ });
قد تقارن الخوارزمية عنصرًا مع عدة عناصر أخرى في العملية، ولكنها تحاول إجراء أقل عدد ممكن من المقارنات.
قد تقوم دالة المقارنة بإرجاع أي رقم
في الواقع، وظيفة المقارنة مطلوبة فقط لإرجاع رقم موجب للقول "أكبر" ورقم سالب للقول "أقل".
يسمح ذلك بكتابة وظائف أقصر:
دع arr = [ 1, 2, 15 ]; arr.sort(function(a, b) { return a - b; }); تنبيه(arr); // 1، 2، 15
وظائف السهم للأفضل
تذكر وظائف السهم؟ يمكننا استخدامها هنا لفرز أكثر دقة:
arr.sort( (a, b) => a - b );
يعمل هذا تمامًا مثل الإصدار الأطول أعلاه.
استخدم localeCompare
للسلاسل
تذكر خوارزمية مقارنة السلاسل؟ يقوم بمقارنة الحروف حسب رموزها بشكل افتراضي.
بالنسبة للعديد من الأبجديات، من الأفضل استخدام طريقة str.localeCompare
لفرز الحروف بشكل صحيح، مثل Ö
.
على سبيل المثال، دعونا نفرز بعض البلدان باللغة الألمانية:
دع البلدان = ["Österreich"، "أندورا"، "فيتنام"]؛ تنبيه(countries.sort( (a, b) => a > b ? 1 : -1) ); // أندورا، فيتنام، Österreich (خطأ) تنبيه(countries.sort( (a, b) => a.localeCompare(b) )); // أندورا، Österreich، فيتنام (صحيح!)
يعكس التابع arr.reverse ترتيب العناصر في arr
.
على سبيل المثال:
دع arr = [1, 2, 3, 4, 5]; arr.reverse(); تنبيه(آر); // 5,4,3,2,1
كما تقوم أيضًا بإرجاع المصفوفة arr
بعد الانعكاس.
هذا هو الوضع من الحياة الحقيقية. نحن نكتب تطبيق مراسلة، ويقوم الشخص بإدخال قائمة المستلمين المفصولة بفواصل: John, Pete, Mary
. ولكن بالنسبة لنا، فإن مجموعة من الأسماء ستكون أكثر راحة من سلسلة واحدة. كيفية الحصول عليه؟
تقوم طريقة str.split(delim) بذلك بالضبط. يقوم بتقسيم السلسلة إلى مصفوفة بواسطة المحدد المحدد delim
.
في المثال أدناه، قمنا بالتقسيم بفاصلة تليها مسافة:
اسمحوا الأسماء = 'بيلبو، غاندالف، نازغول'؛ Let arr =names.split(','); لـ (اسمحوا اسم آر) { تنبيه( `رسالة إلى ${name}.` ); // رسالة إلى بيلبو (والأسماء الأخرى) }
يحتوي أسلوب split
على وسيطة رقمية ثانية اختيارية - حد لطول المصفوفة. إذا تم توفيره، فسيتم تجاهل العناصر الإضافية. في الممارسة العملية، نادرا ما يتم استخدامه على الرغم من:
Let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2); تنبيه(arr); // بيلبو، غاندالف
مقسمة إلى حروف
سيؤدي استدعاء split(s)
باستخدام الحرف s
الفارغ إلى تقسيم السلسلة إلى مجموعة من الأحرف:
دع str = "اختبار"؛ تنبيه( str.split('')); // امتحان
المكالمة arr.join(glue) تفعل العكس split
. يقوم بإنشاء سلسلة من عناصر arr
المرتبطة glue
فيما بينها.
على سبيل المثال:
Let arr = ['Bilbo', 'Gandalf', 'Nazgul']; دع str = arr.join(';'); // ألصق المصفوفة في سلسلة باستخدام ; تنبيه (شارع)؛ // بيلبو؛ غاندالف؛ نازغول
عندما نحتاج إلى التكرار على مصفوفة، يمكننا استخدام forEach
for
أو for..of
.
عندما نحتاج إلى تكرار البيانات وإرجاعها لكل عنصر، يمكننا استخدام map
.
تنتمي الطريقتان arr.reduce وarr.reduceRight أيضًا إلى تلك السلالة، ولكنها أكثر تعقيدًا بعض الشيء. يتم استخدامها لحساب قيمة واحدة بناءً على المصفوفة.
بناء الجملة هو:
دع القيمة = arr.reduce(function(accumulator, item, Index, array) { // ... }، [أولي])؛
يتم تطبيق الوظيفة على جميع عناصر المصفوفة واحدًا تلو الآخر و"تستمر" نتيجتها إلى الاستدعاء التالي.
الحجج:
accumulator
- هو نتيجة استدعاء الوظيفة السابقة، ويساوي initial
في المرة الأولى (إذا تم توفير initial
).
item
- هو عنصر الصفيف الحالي.
index
– هو موقفه.
array
- هي المصفوفة.
عند تطبيق الدالة، يتم تمرير نتيجة استدعاء الدالة السابقة إلى الدالة التالية باعتبارها الوسيطة الأولى.
لذا، فإن الوسيطة الأولى هي في الأساس المُراكم الذي يخزن النتيجة المجمعة لجميع عمليات التنفيذ السابقة. وفي النهاية يصبح نتيجة reduce
.
يبدو معقدا؟
أسهل طريقة لفهم ذلك هي بالقدوة.
هنا نحصل على مجموع مجموعة في سطر واحد:
دع arr = [1, 2, 3, 4, 5]; Let result = arr.reduce((sum,current) => sum +current,0); تنبيه (نتيجة)؛ // 15
تستخدم الدالة التي تم تمريرها reduce
وسيطتين فقط، وهذا يكفي عادةً.
دعونا نرى تفاصيل ما يجري.
في التشغيل الأول، يكون sum
هو القيمة initial
(الوسيطة الأخيرة reduce
)، ويساوي 0
، current
هو عنصر المصفوفة الأول، ويساوي 1
. وبالتالي فإن نتيجة الدالة هي 1
.
في الجولة الثانية، sum = 1
، نضيف عنصر المصفوفة الثاني ( 2
) إليه ونعود.
في الجولة الثالثة، sum = 3
ونضيف إليه عنصرًا آخر، وهكذا...
التدفق الحسابي:
أو على شكل جدول، حيث يمثل كل صف استدعاء دالة على عنصر المصفوفة التالي:
sum | current | نتيجة | |
---|---|---|---|
المكالمة الأولى | 0 | 1 | 1 |
المكالمة الثانية | 1 | 2 | 3 |
المكالمة الثالثة | 3 | 3 | 6 |
المكالمة الرابعة | 6 | 4 | 10 |
المكالمة الخامسة | 10 | 5 | 15 |
هنا يمكننا أن نرى بوضوح كيف تصبح نتيجة الاستدعاء السابق هي الوسيطة الأولى للمكالمة التالية.
يمكننا أيضًا حذف القيمة الأولية:
دع arr = [1, 2, 3, 4, 5]; // إزالة القيمة الأولية من التخفيض (لا 0) Let result = arr.reduce((sum,current) => sum +current); تنبيه (النتيجة)؛ // 15
والنتيجة هي نفسها. وذلك لأنه إذا لم يكن هناك قيمة أولية، فإن reduce
يأخذ العنصر الأول من المصفوفة كقيمة أولية ويبدأ التكرار من العنصر الثاني.
جدول الحساب هو نفسه المذكور أعلاه، باستثناء الصف الأول.
لكن مثل هذا الاستخدام يتطلب عناية شديدة. إذا كانت المصفوفة فارغة، فإن reduce
الاستدعاء بدون قيمة أولية يعطي خطأ.
هنا مثال:
دع arr = []; // خطأ: تقليل المصفوفة الفارغة بدون قيمة أولية // إذا كانت القيمة الأولية موجودة، فسيتم إرجاعها إلى القيمة الفارغة. arr.reduce((المجموع, الحالي) => المجموع + الحالي);
لذا ينصح دائمًا بتحديد القيمة الأولية.
الطريقة arr.reduceRight تفعل الشيء نفسه ولكنها تنتقل من اليمين إلى اليسار.
لا تشكل المصفوفات نوع لغة منفصلاً. أنها تعتمد على الأشياء.
لذا فإن typeof
لا يساعد في التمييز بين كائن عادي ومصفوفة:
تنبيه (نوع {})؛ // هدف تنبيه(نوع []); // الكائن (نفسه)
…ولكن يتم استخدام المصفوفات كثيرًا لدرجة أن هناك طريقة خاصة لذلك: Array.isArray(value). تُرجع true
إذا كانت value
عبارة عن مصفوفة، وتُرجع false
إذا كانت القيمة بخلاف ذلك.
تنبيه(Array.isArray({})); // خطأ شنيع تنبيه(Array.isArray([])); // حقيقي
تقبل جميع توابع المصفوفات تقريبًا التي تستدعي الدوال، مثل find
و filter
و map
، مع استثناء ملحوظ sort
، معلمة إضافية اختيارية thisArg
.
لم يتم شرح هذه المعلمة في الأقسام أعلاه، لأنها نادرًا ما يتم استخدامها. ولكن من أجل اكتمالها، علينا أن نغطيها.
إليك بناء الجملة الكامل لهذه الأساليب:
arr.find(func, thisArg); arr.filter(func, thisArg); arr.map(func, thisArg); // ... // thisArg هي الوسيطة الأخيرة الاختيارية
تصبح قيمة المعلمة thisArg
this
لـ func
.
على سبيل المثال، نستخدم هنا طريقة كائن army
كمرشح، ويقوم thisArg
بتمرير السياق:
دع الجيش = { الحد الأدنى: 18، الحد الأقصى للعمر: 27، يمكن الانضمام (المستخدم) { return user.age >= this.minAge && user.age < this.maxAge; } }; السماح للمستخدمين = [ {العمر: 16}، {العمر: 20}، {العمر: 23}، {العمر: 30} ]; // ابحث عن المستخدمين الذين يعود موقع army.canJoin إليهم صحيحًا دع الجنود = users.filter(army.canJoin, army); تنبيه (الجنود. الطول)؛ // 2 تنبيه(الجنود[0].age); // 20 تنبيه(الجنود[1].age); // 23
إذا استخدمنا في المثال أعلاه users.filter(army.canJoin)
، فسيتم استدعاء army.canJoin
كدالة مستقلة، مع this=undefined
، مما يؤدي إلى خطأ فوري.
يمكن استبدال استدعاء users.filter(army.canJoin, army)
بـ users.filter(user => army.canJoin(user))
الذي يفعل نفس الشيء. يتم استخدام الأخير في كثير من الأحيان، لأنه أسهل قليلاً في الفهم بالنسبة لمعظم الناس.
ورقة الغش لطرق المصفوفة:
لإضافة/إزالة العناصر:
push(...items)
- يضيف العناصر إلى النهاية،
pop()
- يستخرج العنصر من النهاية،
shift()
- يستخرج عنصرًا من البداية،
unshift(...items)
- يضيف العناصر إلى البداية.
splice(pos, deleteCount, ...items)
- في فهرس pos
يحذف عناصر deleteCount
ويدرج items
.
slice(start, end)
- تنشئ مصفوفة جديدة، وتنسخ العناصر من start
الفهرس حتى end
(غير شاملة) بداخلها.
concat(...items)
- يُرجع مصفوفة جديدة: ينسخ جميع أعضاء المصفوفة الحالية ويضيف items
إليها. إذا كان أي من items
عبارة عن مصفوفة، فسيتم أخذ عناصرها.
للبحث بين العناصر:
indexOf/lastIndexOf(item, pos)
– ابحث عن item
بدءًا من الموضع pos
وأعد الفهرس أو -1
إذا لم يتم العثور عليه.
includes(value)
- تُرجع true
إذا كانت المصفوفة تحتوي على value
، وإلا فإنها false
.
find/filter(func)
- تصفية العناصر من خلال الوظيفة، وإرجاع أول/جميع القيم التي تجعلها تُرجع true
.
findIndex
يشبه find
، ولكنه يُرجع الفهرس بدلاً من القيمة.
للتكرار على العناصر:
forEach(func)
- يستدعي func
لكل عنصر، ولا يُرجع أي شيء.
لتحويل المصفوفة:
map(func)
- ينشئ مصفوفة جديدة من نتائج استدعاء func
لكل عنصر.
sort(func)
– يفرز المصفوفة في مكانها، ثم يعيدها.
reverse()
- يعكس المصفوفة في مكانها، ثم يعيدها.
split/join
- تحويل السلسلة إلى صفيف والعودة.
reduce/reduceRight(func, initial)
- حساب قيمة واحدة على المصفوفة عن طريق استدعاء func
لكل عنصر وتمرير نتيجة وسيطة بين الاستدعاءات.
بالإضافة إلى ذلك:
يتحقق Array.isArray(value)
من value
لكونها مصفوفة، وإذا كان الأمر كذلك فإنها تُرجع true
، وإلا فستُرجع false
.
يرجى ملاحظة أن طرق sort
reverse
splice
تعدل المصفوفة نفسها.
هذه الطرق هي الأكثر استخدامًا، فهي تغطي 99% من حالات الاستخدام. ولكن هناك عدد قليل من الآخرين:
arr.some(fn)/arr.every(fn) تحقق من المصفوفة.
يتم استدعاء الدالة fn
على كل عنصر من عناصر المصفوفة بشكل مشابه map
. إذا كانت أي/جميع النتائج true
، فسيتم إرجاعها true
، وإلا فستُرجع false
.
تتصرف هذه الأساليب نوعًا ما مثل ||
ومعاملي &&
: إذا أعادت fn
قيمة صحيحة، فإن arr.some()
تُرجع فورًا true
وتتوقف عن التكرار على بقية العناصر؛ إذا أعاد fn
قيمة خاطئة، فسيُرجع الدالة arr.every()
على الفور القيمة false
ويتوقف عن التكرار على بقية العناصر أيضًا.
يمكننا استخدام every
لمقارنة المصفوفات:
صفائف الدالةEqual(arr1, arr2) { return arr1.length === arr2.length && arr1.every((value, Index) => value === arr2[index]); } تنبيه( المصفوفاتEqual([1, 2], [1, 2])); // حقيقي
arr.fill(value, start, end) - يملأ المصفوفة value
متكررة من start
الفهرس إلى end
.
arr.copyWithin(target, start, end) - ينسخ عناصره من موضع start
حتى end
الموضع إلى نفسه ، عند الموضع target
(يستبدل الموجود).
arr.flat(العمق)/arr.flatMap(fn) ينشئ مصفوفة مسطحة جديدة من مصفوفة متعددة الأبعاد.
للحصول على القائمة الكاملة، راجع الدليل.
للوهلة الأولى، قد يبدو أن هناك العديد من الطرق التي يصعب تذكرها. ولكن في الواقع، هذا أسهل بكثير.
انظر إلى ورقة الغش فقط لتكون على علم بها. ثم قم بحل مهام هذا الفصل للتدرب عليها، حتى تكون لديك خبرة في طرق المصفوفة.
بعد ذلك، عندما تحتاج إلى القيام بشيء ما باستخدام مصفوفة، ولا تعرف كيف - تعال إلى هنا، وانظر إلى ورقة الغش وابحث عن الطريقة الصحيحة. سوف تساعدك الأمثلة على كتابتها بشكل صحيح. وسرعان ما ستتذكر الطرق تلقائيًا، دون بذل أي جهد محدد من جانبك.
الأهمية: 5
اكتب الدالة camelize(str)
التي تغير الكلمات المفصولة بشرطة مثل "my-short-string" إلى "myShortString" المكتوبة بحروف الجمل.
أي: إزالة جميع الشرطات، بحيث تصبح كل كلمة بعد الشرطة مكتوبة بأحرف كبيرة.
أمثلة:
Camelize("background-color") == 'backgroundColor'; Camelize("list-style-image") == 'listStyleImage'; Camelize("-webkit-transition") == 'WebkitTransition';
تلميح ملاحظة: استخدم split
لتقسيم السلسلة إلى مصفوفة، وتحويلها join
مرة أخرى.
افتح صندوق الرمل مع الاختبارات.
وظيفة Camelize (شارع) { شارع العودة .split('-') // يقسم 'my-long-word' إلى مصفوفة ['my', 'long', 'word'] .رسم خريطة( // تكبير الأحرف الأولى من جميع عناصر المصفوفة باستثناء الحرف الأول // يحول ['my'، 'long'، 'word'] إلى ['my'، 'Long'، 'Word'] (كلمة، فهرس) => فهرس == 0؟ الكلمة: كلمة [0].toUpperCase () + كلمة. شريحة (1) ) .ينضم('')؛ // ينضم ['my'، 'Long'، 'Word'] إلى 'myLongWord' }
افتح الحل بالاختبارات في وضع الحماية.
الأهمية: 4
اكتب دالة filterRange(arr, a, b)
تحصل على مصفوفة arr
، وتبحث عن عناصر ذات قيم أعلى أو تساوي a
وأقل أو تساوي b
وترجع النتيجة على شكل مصفوفة.
يجب ألا تقوم الدالة بتعديل الصفيف. يجب أن يعود المصفوفة الجديدة.
على سبيل المثال:
دع arr = [5, 3, 8, 1]; Let filtered = filterRange(arr, 1, 4); تنبيه (تمت تصفيته)؛ // 3,1 (القيم المطابقة) تنبيه(آر); // 5،3،8،1 (لم يتم تعديله)
افتح صندوق الرمل مع الاختبارات.
وظيفة مرشح المدى (arr، a، b) { // تمت إضافة أقواس حول التعبير لتسهيل القراءة return arr.filter(item => (a <= item && item <= b)); } دع arr = [5, 3, 8, 1]; Let filtered = filterRange(arr, 1, 4); تنبيه (تمت تصفيته)؛ // 3,1 (القيم المطابقة) تنبيه(آر); // 5،3،8،1 (لم يتم تعديله)
افتح الحل بالاختبارات في وضع الحماية.
الأهمية: 4
اكتب دالة filterRangeInPlace(arr, a, b)
التي تحصل على مصفوفة arr
وتزيل منها جميع القيم باستثناء تلك التي تقع بين a
و b
. الاختبار هو: a ≤ arr[i] ≤ b
.
يجب أن تقوم الوظيفة بتعديل المصفوفة فقط. لا ينبغي أن يعود أي شيء.
على سبيل المثال:
دع arr = [5, 3, 8, 1]; filterRangeInPlace(arr, 1, 4); // إزالة الأرقام ما عدا من 1 إلى 4 تنبيه(آر); // [3، 1]
افتح صندوق الرمل مع الاختبارات.
وظيفة تصفيةRangeInPlace(arr, a, b) { لـ (دع i = 0; i < arr.length; i++) { Let val = arr[i]; // إزالة إذا كان خارج الفاصل الزمني إذا (فال <أ || فال > ب) { arr.splice(i, 1); أنا--؛ } } } دع arr = [5, 3, 8, 1]; filterRangeInPlace(arr, 1, 4); // إزالة الأرقام ما عدا من 1 إلى 4 تنبيه(آر); // [3، 1]
افتح الحل بالاختبارات في وضع الحماية.
الأهمية: 4
دع arr = [5، 2، 1، -10، 8]؛ // ... الكود الخاص بك لفرزه بترتيب تنازلي تنبيه(آر); // 8، 5، 2، 1، -10
دع arr = [5، 2، 1، -10، 8]؛ arr.sort((a, b) => b - a); تنبيه(آر);
الأهمية: 5
لدينا مجموعة من السلاسل arr
. نود أن نحصل على نسخة مرتبة منه، لكن arr
بدون تعديل.
قم بإنشاء وظيفة copySorted(arr)
التي تقوم بإرجاع مثل هذه النسخة.
Let arr = ["HTML"، "JavaScript"، "CSS"]؛ دع فرزها = CopySorted(arr); تنبيه (مرتبة)؛ // CSS، HTML، جافا سكريبت تنبيه(آر); // HTML، وJavaScript، وCSS (بدون تغييرات)
يمكننا استخدام slice()
لعمل نسخة وإجراء عملية الفرز عليها:
الدالة CopySorted(arr) { إرجاع arr.slice().sort(); } Let arr = ["HTML"، "JavaScript"، "CSS"]؛ دع فرزها = CopySorted(arr); تنبيه (مرتبة)؛ تنبيه(آر);
الأهمية: 5
قم بإنشاء Calculator
دالة منشئة تقوم بإنشاء كائنات حاسبة "قابلة للتمديد".
تتكون المهمة من جزأين.
أولاً، قم بتنفيذ طريقة calculate(str)
التي تأخذ سلسلة مثل "1 + 2"
بتنسيق "عامل التشغيل NUMBER NUMBER" (مفصول بمسافات) وتقوم بإرجاع النتيجة. ينبغي أن يفهم زائد +
وناقص -
.
مثال الاستخدام:
Let calc = حاسبة جديدة؛ تنبيه(calc.calculate("3 + 7")); // 10
ثم أضف الطريقة addMethod(name, func)
التي تعلم الآلة الحاسبة عملية جديدة. يأخذ name
المشغل والدالة ذات الوسيطتين func(a,b)
التي تنفذه.
على سبيل المثال، دعونا نضيف الضرب *
والقسمة /
والقوة **
:
دع powerCalc = حاسبة جديدة؛ powerCalc.addMethod("*", (a, b) => a * b); powerCalc.addMethod("/", (a, b) => a / b); powerCalc.addMethod("**", (a, b) => a ** b); دع النتيجة = powerCalc.calculate("2 ** 3"); تنبيه (النتيجة)؛ // 8
لا توجد أقواس أو تعبيرات معقدة في هذه المهمة.
يتم تحديد الأرقام والمشغل بمسافة واحدة بالضبط.
قد يكون هناك خطأ في التعامل إذا كنت ترغب في إضافته.
افتح صندوق الرمل مع الاختبارات.
يرجى ملاحظة كيفية تخزين الأساليب. يتم إضافتها ببساطة إلى خاصية this.methods
.
تتم جميع الاختبارات والتحويلات الرقمية بطريقة calculate
. في المستقبل قد يتم توسيعه لدعم تعبيرات أكثر تعقيدًا.
حاسبة الدالة () { هذه الأساليب = { "-": (أ، ب) => أ - ب، "+": (أ، ب) => أ + ب }; هذا. احسب = وظيفة (شارع) { دع الانقسام = str.split (' ')، أ = +تقسيم[0]، المرجع = تقسيم [1]، ب = +سبليت[2]; إذا (!this.methods[op] || isNaN(a) || isNaN(b)) { إرجاع نان؛ } إرجاع this.methods[op](a, b); }; this.addMethod = function(name, func) { this.methods[name] = func; }; }
افتح الحل بالاختبارات في وضع الحماية.
الأهمية: 5
لديك مصفوفة من كائنات user
، كل منها يحمل user.name
. اكتب الكود الذي يحوله إلى مجموعة من الأسماء.
على سبيل المثال:
Let john = { الاسم: "جون"، العمر: 25 }; Let pete = { الاسم: "بيت"، العمر: 30 }; Let Mary = { الاسم: "مريم"، العمر: 28 }; السماح للمستخدمين = [جون، بيت، ماري]؛ دع الأسماء = /* ... الكود الخاص بك */ تنبيه (أسماء)؛ // جون، بيت، ماري
Let john = { الاسم: "جون"، العمر: 25 }; Let pete = { الاسم: "بيت"، العمر: 30 }; Let Mary = { الاسم: "مريم"، العمر: 28 }; السماح للمستخدمين = [جون، بيت، ماري]؛ دع الأسماء = users.map(item => item.name); تنبيه (أسماء)؛ // جون، بيت، ماري
الأهمية: 5
لديك مجموعة من كائنات user
، كل منها له name
surname
id
.
اكتب الكود لإنشاء مصفوفة أخرى منه، للكائنات ذات id
والاسم fullName
، حيث يتم إنشاء fullName
من name
surname
.
على سبيل المثال:
Let john = { الاسم: "جون"، اللقب: "سميث"، المعرف: 1 }; Let pete = { الاسم: "Pete"، اللقب: "Hunt"، المعرف: 2 }; Let Mary = { الاسم: "ماري"، اللقب: "مفتاح"، المعرف: 3 }; السماح للمستخدمين = [جون، بيت، ماري]؛ دع usersMapped = /* ... الكود الخاص بك ... */ /* المستخدمين مابيد = [ { الاسم الكامل: "جون سميث"، المعرف: 1 }، { الاسم الكامل: "بيت هانت"، المعرف: 2 }، { الاسم الكامل: "ماري كي"، المعرف: 3 } ] */ تنبيه (usersMapped[0].id) // 1 تنبيه (usersMapped[0].fullName) // جون سميث
لذلك، في الواقع تحتاج إلى تعيين مجموعة من الكائنات إلى أخرى. حاول استخدام =>
هنا. هناك صيد صغير.
Let john = { الاسم: "جون"، اللقب: "سميث"، المعرف: 1 }; Let pete = { الاسم: "Pete"، اللقب: "Hunt"، المعرف: 2 }; Let Mary = { الاسم: "ماري"، اللقب: "مفتاح"، المعرف: 3 }; السماح للمستخدمين = [جون، بيت، ماري]؛ دع usersMapped = users.map(user => ({ الاسم الكامل: `${user.name} ${user.surname}`، المعرف: معرف المستخدم })); /* المستخدمين مابيد = [ { الاسم الكامل: "جون سميث"، المعرف: 1 }، { الاسم الكامل: "بيت هانت"، المعرف: 2 }، { الاسم الكامل: "ماري كي"، المعرف: 3 } ] */ تنبيه (usersMapped[0].id ); // 1 تنبيه (usersMapped[0].fullName ); // جون سميث
يرجى ملاحظة أنه في وظائف الأسهم نحتاج إلى استخدام أقواس إضافية.
لا نستطيع أن نكتب هكذا:
اسمح للمستخدمينMapped = users.map(user => { الاسم الكامل: `${user.name} ${user.surname}`، المعرف: معرف المستخدم });
كما نتذكر، هناك وظيفتان للسهم: بدون value => expr
value => {...}
.
هنا ستتعامل JavaScript مع {
كبداية لجسم الوظيفة، وليس بداية الكائن. الحل البديل هو وضعها بين قوسين "عاديين":
دع usersMapped = users.map(user => ({ الاسم الكامل: `${user.name} ${user.surname}`، المعرف: معرف المستخدم }));
الآن بخير.
الأهمية: 5
اكتب الدالة sortByAge(users)
التي تحصل على مصفوفة من الكائنات ذات الخاصية age
وتقوم بفرزها حسب age
.
على سبيل المثال:
Let john = { الاسم: "جون"، العمر: 25 }; Let pete = { الاسم: "بيت"، العمر: 30 }; Let Mary = { الاسم: "مريم"، العمر: 28 }; دع arr = [بيت، جون، ماري]؛ SortByAge(arr); // الآن: [جون، ماري، بيت] تنبيه(arr[0].name); // جون تنبيه(arr[1].name); // ماري تنبيه(arr[2].name); // بيت
وظيفة سورتبياج (آر) { arr.sort((a, b) => a.age - b.age); } Let john = { الاسم: "جون"، العمر: 25 }; Let pete = { الاسم: "بيت"، العمر: 30 }; Let Mary = { الاسم: "مريم"، العمر: 28 }; دع arr = [بيت، جون، ماري]؛ SortByAge(arr); // الترتيب الآن هو: [جون، ماري، بيت] تنبيه(arr[0].name); // جون تنبيه(arr[1].name); // ماري تنبيه(arr[2].name); // بيت
الأهمية: 3
اكتب الدالة shuffle(array)
التي تقوم بخلط عناصر المصفوفة (إعادة ترتيبها عشوائيًا).
قد تؤدي عمليات التشغيل المتعددة shuffle
إلى ترتيبات مختلفة للعناصر. على سبيل المثال:
دع arr = [1, 2, 3]; خلط ورق اللعب(arr); // آر = [3، 2، 1] خلط ورق اللعب(arr); // آر = [2، 1، 3] خلط ورق اللعب(arr); // آر = [3، 1، 2] // ...
يجب أن يكون لجميع أوامر العناصر احتمالية متساوية. على سبيل المثال، يمكن إعادة ترتيب [1,2,3]
إلى [1,2,3]
أو [1,3,2]
أو [3,1,2]
وما إلى ذلك، مع احتمالية متساوية لكل حالة.
الحل البسيط يمكن أن يكون:
وظيفة خلط ورق اللعب (صفيف) { array.sort(() => Math.random() - 0.5); } دع arr = [1, 2, 3]; خلط ورق اللعب(arr); تنبيه(arr);
يعمل هذا إلى حد ما، لأن Math.random() - 0.5
هو رقم عشوائي قد يكون موجبًا أو سالبًا، لذا تقوم وظيفة الفرز بإعادة ترتيب العناصر بشكل عشوائي.
ولكن نظرًا لأن دالة الفرز ليس المقصود استخدامها بهذه الطريقة، فليست كل التباديل لها نفس الاحتمال.
على سبيل المثال، خذ بعين الاعتبار الكود أدناه. إنه يعمل على shuffle
1000000 مرة ويعتبر المظاهر لجميع النتائج الممكنة:
وظيفة Shuffle (Array) { Array.sort (() => Math.Random () - 0.5) ؛ } // تهم المظاهر لجميع التباديل الممكنة دع العد = { '123': 0 ، '132': 0 ، '213': 0 ، '231': 0 ، '321': 0 ، '312': 0 }; لـ (دعني i = 0 ؛ i <1000000 ؛ i ++) { دع الصفيف = [1 ، 2 ، 3] ؛ خلط ورق اللعب (صفيف) ؛ count [array.join ('')] ++ ؛ } // إظهار تهم جميع التباديل الممكنة ل (دع المفتاح في العد) { ALERT (`$ {key}: $ {count [key]}`) ؛ }
نتيجة مثال (يعتمد على محرك JS):
123: 250706 132: 124425 213: 249618 231: 124880 312: 125148 321: 125223
يمكننا أن نرى التحيز بوضوح: 123
و 213
يظهران في كثير من الأحيان أكثر من الآخرين.
قد تختلف نتيجة الكود بين محركات JavaScript ، ولكن يمكننا بالفعل أن نرى أن النهج غير موثوق به.
لماذا لا يعمل؟ بشكل عام ، يعد sort
"صندوقًا أسود": نرمي صفيفًا ووظيفة مقارنة فيه ونتوقع فرز الصفيف. ولكن نظرًا للعشوائية المطلقة للمقارنة ، فإن المربع الأسود يشعر بالجنون ، وكيف أن الجنون بالضبط يعتمد على التنفيذ الملموس الذي يختلف بين المحركات.
هناك طرق جيدة أخرى للقيام بهذه المهمة. على سبيل المثال ، هناك خوارزمية رائعة تسمى Fisher-Yates Shuffle. الفكرة هي السير في الصفيف بالترتيب العكسي ومبادلة كل عنصر مع واحد عشوائي قبل ذلك:
وظيفة Shuffle (Array) { لـ (دع i = array.length-1 ؛ i> 0 ؛ i--) { دع j = math.floor (math.random () * (i + 1)) ؛ // فهرس عشوائي من 0 إلى أنا // Swap Elements Array [i] و Array [J] // نستخدم بناء جملة "تدمير مهمة" لتحقيق ذلك // ستجد المزيد من التفاصيل حول هذا الجملة في الفصول اللاحقة // يمكن كتابة نفس الشيء على النحو التالي: // دع t = صفيف [i] ؛ صفيف [i] = صفيف [j] ؛ صفيف [j] = ر [Array [i] ، Array [J]] = [Array [J] ، Array [i]] ؛ } }
دعنا نختبرها بنفس الطريقة:
وظيفة Shuffle (Array) { لـ (دع i = array.length-1 ؛ i> 0 ؛ i--) { دع j = math.floor (math.random () * (i + 1)) ؛ [Array [i] ، Array [J]] = [Array [J] ، Array [i]] ؛ } } // تهم المظاهر لجميع التباديل الممكنة دع العد = { '123': 0 ، '132': 0 ، '213': 0 ، '231': 0 ، '321': 0 ، '312': 0 }; لـ (دعني i = 0 ؛ i <1000000 ؛ i ++) { دع الصفيف = [1 ، 2 ، 3] ؛ خلط ورق اللعب (صفيف) ؛ count [array.join ('')] ++ ؛ } // إظهار تهم جميع التباديل الممكنة ل (دع المفتاح في العد) { ALERT (`$ {key}: $ {count [key]}`) ؛ }
إخراج المثال:
123: 166693 132: 166647 213: 166628 231: 167517 312: 166199 321: 166316
يبدو جيدًا الآن: تظهر جميع التباديل بنفس الاحتمال.
أيضا ، من ناحية الأداء خوارزمية فيشر ييتس أفضل بكثير ، لا يوجد "فرز" النفقات العامة.
الأهمية: 4
اكتب وظيفة getAverageAge(users)
التي تحصل على مجموعة من الكائنات مع age
الممتلكات وإرجاع متوسط العمر.
صيغة المتوسط هي (age1 + age2 + ... + ageN) / N
.
على سبيل المثال:
دع جون = {الاسم: "جون" ، العمر: 25} ؛ دع Pete = {name: "Pete" ، العمر: 30} ؛ دع ماري = {الاسم: "ماري" ، العمر: 29} ؛ دع arr = [جون ، بيت ، ماري] ؛ تنبيه (getaverageage (arr)) ؛ // (25 + 30 + 29) / 3 = 28
وظيفة getaverageage (المستخدمين) { return users.reduce ((prev ، user) => prev + user.age ، 0) / user.length ؛ } دع جون = {الاسم: "جون" ، العمر: 25} ؛ دع Pete = {name: "Pete" ، العمر: 30} ؛ دع ماري = {الاسم: "ماري" ، العمر: 29} ؛ دع arr = [جون ، بيت ، ماري] ؛ تنبيه (getaverageage (arr)) ؛ // 28
الأهمية: 4
arr
صفيفًا.
قم بإنشاء وظيفة unique(arr)
يجب أن تُرجع مجموعة مع عناصر فريدة من arr
.
على سبيل المثال:
وظيفة فريدة (arr) { / * الكود الخاص بك */ } دع السلاسل = ["Hare" ، "Krishna" ، "Hare" ، "Krishna" ، "كريشنا" ، "كريشنا" ، "هير" ، "هير" ، ": -o" ]; تنبيه (فريد (سلاسل)) ؛ // هير ، كريشنا ،: -o
افتح صندوق الرمل مع الاختبارات.
دعنا نسير عناصر الصفيف:
لكل عنصر سنتحقق مما إذا كان الصفيف الناتج يحتوي بالفعل على هذا العنصر.
إذا كان الأمر كذلك ، فتجاهل ، وإلا أضف إلى النتائج.
وظيفة فريدة (arr) { دع النتيجة = [] ؛ لـ (دع str of arr) { if (! result.includes (str)) { النتيجة. push (str) ؛ } } نتيجة الإرجاع؛ } دع السلاسل = ["Hare" ، "Krishna" ، "Hare" ، "Krishna" ، "كريشنا" ، "كريشنا" ، "هير" ، "هير" ، ": -o" ]; تنبيه (فريد (سلاسل)) ؛ // هير ، كريشنا ،: -o
يعمل الرمز ، ولكن هناك مشكلة في الأداء المحتملة فيه.
result.includes(str)
يسير داخليًا إلى result
الصفيف ويقارن كل عنصر ضد str
للعثور على المباراة.
لذلك إذا كان هناك 100
عنصر في result
ولم يكن أحد يطابق str
، فسوف يمشي على result
بأكملها وتفعل 100
مقارنات بالضبط. وإذا كانت result
كبيرة ، مثل 10000
، فستكون هناك 10000
مقارنات.
هذه ليست مشكلة في حد ذاتها ، لأن محركات JavaScript سريعة جدًا ، لذا فإن مجموعة Walk 10000
هي مسألة ميكروثانية.
لكننا نقوم بهذا الاختبار لكل عنصر من عناصر arr
، في for
.
لذلك إذا كان arr.length
هو 10000
فسنحصل على 10000*10000
= 100 مليون من المقارنات. هذا كثير.
وبالتالي فإن الحل مفيد فقط للصفائف الصغيرة.
علاوة على ذلك في خريطة الفصل ، سنرى كيفية تحسينه.
افتح الحل بالاختبارات في وضع الحماية.
الأهمية: 4
دعنا نقول أننا تلقينا مجموعة من المستخدمين في النموذج {id:..., name:..., age:... }
.
قم بإنشاء وظيفة groupById(arr)
تقوم بإنشاء كائن منه ، مع id
كمفتاح ، وعناصر الصفيف كقيم.
على سبيل المثال:
دع المستخدمين = [ {id: 'John' ، الاسم: "John Smith" ، العمر: 20} ، {id: 'Ann' ، الاسم: "Ann Smith" ، العمر: 24} ، {id: 'pete' ، الاسم: "بيت بيترسون" ، العمر: 31} ، ]; دع المستخدمين = groupById (المستخدمين) ؛ /* // بعد المكالمة يجب أن يكون لدينا: usersbyid = { جون: {id: 'John' ، الاسم: "John Smith" ، العمر: 20} ، Ann: {id: 'Ann' ، الاسم: "Ann Smith" ، العمر: 24} ، بيت: {id: 'بيت' ، الاسم: "بيت بيترسون" ، العمر: 31} ، } */
هذه الوظيفة مفيدة حقًا عند العمل مع بيانات الخادم.
في هذه المهمة ، نفترض أن id
فريد من نوعه. قد لا يكون هناك عناصر صفيف مع نفس id
.
يرجى استخدام طريقة .reduce
في الحل.
افتح صندوق الرمل مع الاختبارات.
وظيفة groupbyid (صفيف) { return array.reduce ((obj ، value) => { OBJ [value.id] = value ؛ إرجاع OBJ ؛ } ، {}) }
افتح الحل بالاختبارات في وضع الحماية.