نقدم لك ترجمة لمقال بقلم توماس لومبارت ، والذي نشر على medium.freecodecamp.org. يتم نشر الترجمة بإذن من المؤلف.
مثال على استخدام طريقة التصغير لتقليل الصفيفاسمح لي بالإدلاء ببيان جريء: الحلقات غالبًا ما تكون عديمة الفائدة وتجعل قراءة التعليمات البرمجية صعبة. بالنسبة للتكرارات في المصفوفات والبحث عن العناصر والفرز والإجراءات المماثلة الأخرى ، يمكنك استخدام إحدى الطرق أدناه.
على الرغم من الفعالية ، لا تزال معظم هذه الأساليب غير معروفة ولا تحظى بشعبية كبيرة. سأقوم بالعمل الشاق من أجلك والحديث عن أكثر فائدة. اقرأ هذه المقالة كدليل لطرق صفيف JavaScript.
ملاحظة : قبل أن نبدأ ، تحتاج إلى معرفة شيء واحد: أنا منحازة نحو البرمجة الوظيفية. لتجنب الآثار الجانبية ، أسعى لتطبيق الأساليب التي لا تعدل الصفيف الأصلي مباشرةً. أنا لا أخبرك برفض تغيير الصفيف على الإطلاق ، لكن تجدر الإشارة إلى أن بعض الطرق تؤدي إلى ذلك. نتيجة لذلك ، تظهر الآثار الجانبية والتغييرات غير المرغوب فيها ، ونتيجة لذلك ، تظهر الأخطاء.
تم نشر هذا المقال في الأصل على
thomlom.dev ، حيث يمكنك العثور على المزيد من مواد تطوير الويب.
الأساسيات
هناك أربع طرق تستحق معرفة ما إذا كنت تعمل مع المصفوفات. هذه هي
map
،
filter
،
reduce
من
spread
المشغل. أنها فعالة ومفيدة.
الخريطةسوف تستخدم غالبًا طريقة
map
. بشكل عام ، في كل مرة تحتاج فيها إلى تغيير عناصر الصفيف ، ضع في اعتبارك هذا الخيار.
يتطلب الأمر معلمة واحدة - دالة تسمى كل عنصر من عناصر المصفوفة ، ثم تُرجع
صفيفًا جديدًا حتى لا يكون هناك أي آثار جانبية.
const numbers = [1, 2, 3, 4] const numbersPlusOne = numbers.map(n => n + 1) console.log(numbersPlusOne)
يمكنك أيضًا إنشاء صفيف جديد يخزن خاصية محددة واحدة فقط للكائن.
const allActivities = [ { title: 'My activity', coordinates: [50.123, 3.291] }, { title: 'Another activity', coordinates: [1.238, 4.292] } ] const allCoordinates = allActivities.map(activity => activity.coordinates) console.log(allCoordinates)
لذلك ، تذكر: عندما تحتاج إلى
تغيير مجموعة ، فكر في استخدام
الخريطة .
فلتريتحدث اسم هذه الطريقة عن نفسه: استخدمها عندما تريد تصفية صفيف.
مثل
map
، يأخذ
filter
كمعلمة واحدة وظيفة تسمى على كل عنصر من عناصر الصفيف. يجب أن ترجع هذه الدالة قيمة منطقية:
true
- إذا كنت تريد حفظ العنصر في صفيف ؛false
- إذا كنت لا تريد حفظه.
نتيجة لذلك ، سيكون لديك الصفيف الجديد الصحيح مع العناصر التي تريد تركها.
على سبيل المثال ، يمكن تخزين الأرقام الفردية فقط في صفيف.
const numbers = [1, 2, 3, 4, 5, 6] const oddNumbers = numbers.filter(n => n % 2 !== 0) console.log(oddNumbers)
يمكنك أيضًا استخدام عامل التصفية لإزالة عنصر معين في الصفيف.
const participants = [ { id: 'a3f47', username: 'john' }, { id: 'fek28', username: 'mary' }, { id: 'n3j44', username: 'sam' }, ] function removeParticipant(participants, id) { return participants.filter(participant => participant.id !== id) } console.log(removeParticipant(participants, 'a3f47'))
الحدفي رأيي ، هذه الطريقة هي الأصعب في الفهم. ولكن بمجرد إتقانها ، سيكون لديك مجموعة من الفرص.
عادةً ما تأخذ طريقة التصغير صفيفًا من القيم وتسلسلها في قيمة واحدة. يستغرق معلمتين ، وظيفة رد الاتصال (وهو
المخفض ) وقيمة أولية اختيارية (والتي هي العنصر الأول للصفيف بشكل افتراضي). يأخذ صندوق التروس نفسه أربعة معلمات:
- بطارية تجمع القيم المرتجعة في علبة التروس ؛
- القيمة الحالية للصفيف
- الفهرس الحالي
- الصفيف الذي تم استدعاء طريقة
reduce
.
في الأساس سوف تستخدم فقط المعلمتين الأولين - البطارية والقيمة الحالية.
لكن دعونا لا نتعمق في النظرية ونفكر في المثال الأكثر شيوعًا لتطبيق
reduce
.
const numbers = [37, 12, 28, 4, 9] const total = numbers.reduce((total, n) => total + n) console.log(total)
في التكرار الأول ، يأخذ المتراكم ، وهو المجموع ، القيمة الأولية 37. القيمة المعادة هي 37 + ن ، حيث ن = 12. نحصل على 49.
أثناء التكرار الثاني ، يكون المركم هو 49 ، والقيمة التي يتم إرجاعها هي 49 + 28 = 77. وهكذا.
طريقة الاختزال وظيفية للغاية بحيث يمكنك استخدامها لإنشاء العديد من أساليب الصفيف مثل
map
أو
filter
.
const map = (arr, fn) => { return arr.reduce((mappedArr, element) => { return [...mappedArr, fn(element)] }, []) } console.log(map([1, 2, 3, 4], n => n + 1))
كقاعدة عامة ، نقوم بتعيين القيمة الأولية
[]
لطريقة الاختزال - المجمع. بالنسبة إلى
map
فإننا نقوم بتشغيل وظيفة يتم إضافة نتائجها إلى نهاية البطارية باستخدام
مشغل الانتشار (سنتحدث عنها أدناه ، لا تقلق). بالنسبة
filter
بنفس الشيء تقريبًا ، فنحن نقوم بتشغيل وظيفة المرشح فقط على العنصر. إذا كان هذا صحيحًا ، فسنرجع الصفيف
السابق . وإلا ، أضف العنصر إلى نهاية الصفيف.
دعنا ننظر إلى مثال أكثر تعقيدًا: قلل الصفيف إلى حد كبير
[1, 2, 3, [4, [[[5, [6, 7]]]], 8]]
إلى
[1, 2, 3, 4, 5, 6, 7, 8]
.
function flatDeep(arr) { return arr.reduce((flattenArray, element) => { return Array.isArray(element) ? [...flattenArray, ...flatDeep(element)] : [...flattenArray, element] }, []) } console.log(flatDeep([1, 2, 3, [4, [[[5, [6, 7]]]], 8]]))
يشبه هذا المثال
map
، إلا أننا نستخدم العودية هنا. لن أتناول بالتفصيل العودية ، لأن هذا يتجاوز نطاق موضوعنا ، ولكن إذا كنت تريد معرفة المزيد ، فانتقل إلى هذا
المورد الممتاز .
بيان الانتشار (ES2015)أوافق ، هذه ليست طريقة. ومع ذلك ، فإن عامل الانتشار يساعد في تحقيق أهداف مختلفة عند العمل مع المصفوفات. يمكنك تطبيقه لتوسيع قيم صفيف في آخر ، ثم إنشاء نسخة أو ربط عدة صفائف معًا.
const numbers = [1, 2, 3] const numbersCopy = [...numbers] console.log(numbersCopy)
ملاحظة : تقوم عبارة الحيز بعمل
نسخة ضحلة للصفيف الأصلي. ولكن ماذا يعني "السطحية"؟
هذه النسخة ستكرر العناصر الأصلية بأقل قدر ممكن. إذا كان لديك صفيف به أرقام أو سلاسل أو قيم منطقية (
أنواع بدائية ) ، فلا توجد مشاكل وتتكرر القيم بالفعل. ومع ذلك ، تختلف
الأشياء مع
الكائنات والصفائف : يتم نسخ فقط
مرجع إلى القيمة الأصلية. لذلك ، إذا قمت بإنشاء نسخة ضحلة من الصفيف بما في ذلك الكائن وقمت بتغيير الكائن في الصفيف المنسوخ ، فسيتم تغييره أيضًا في الأصل ، لأن له
نفس المرجع .
const arr = ['foo', 42, { name: 'Thomas' }] let copy = [...arr] copy[0] = 'bar' console.log(arr)
لذلك ، إذا كنت ترغب في إنشاء نسخة حقيقية من صفيف يحتوي على كائن أو صفائف ، يمكنك استخدام دالة
lodash مثل
cloneDeep . ولكن لا تعتبر نفسك مضطرًا للقيام بذلك. هدفك هو
معرفة كيف يعمل كل شيء تحت الغطاء .
طرق مفيدة
ستجد أدناه طرقًا أخرى مفيدة للتعرف عليها والتي يمكن أن تكون مفيدة لحل المشكلات مثل البحث عن عنصر في صفيف ، وإزالة جزء من صفيف ، وأكثر من ذلك بكثير.
يشمل (ES2015)هل سبق أن استخدمت
indexOf
لمعرفة ما إذا كان هناك عنصر في صفيف أم لا؟ طريقة رهيبة للتحقق ، أليس كذلك؟
لحسن الحظ ، فإن الأسلوب
includes
التحقق من صحة بالنسبة لنا. قم بتعيين المعلمة لـ include ، وسوف تبحث عن العنصر في الصفيف.
const sports = ['football', 'archery', 'judo'] const hasFootball = sports.includes('football') console.log(hasFootball)
CONCATيمكن استخدام طريقة concat لدمج صفيفين أو أكثر.
const numbers = [1, 2, 3] const otherNumbers = [4, 5, 6] const numbersConcatenated = numbers.concat(otherNumbers) console.log(numbersConcatenated)
forEachإذا كنت تريد تنفيذ إجراء لكل عنصر من عناصر الصفيف ، يمكنك استخدام الأسلوب
forEach
. تأخذ وظيفة كمعلمة ، والتي بدورها تأخذ أيضًا ثلاثة معلمات: القيمة الحالية ، والفهرس ، والصفيف.
const numbers = [1, 2, 3, 4, 5] numbers.forEach(console.log)
indexOfتُستخدم هذه الطريقة لإرجاع الفهرس الأول حيث يمكن العثور على العنصر في الصفيف. أيضًا ،
indexOf
غالبًا عن وجود عنصر في صفيف. بصراحة ، الآن أنا استخدامها بشكل غير منتظم.
const sports = ['football', 'archery', 'judo'] const judoIndex = sports.indexOf('judo') console.log(judoIndex)
اكتشافطريقة
find
تشبه
filter
. تحتاج إلى تزويدها بوظيفة تختبر كل عنصر من عناصر الصفيف. ومع ذلك ،
find
عن توقف عن اختبار العناصر بمجرد العثور على أحد اجتاز الاختبار. هذا
ليس filter
يتكرر على الصفيف بأكمله بغض النظر عن الظروف.
const users = [ { id: 'af35', name: 'john' }, { id: '6gbe', name: 'mary' }, { id: '932j', name: 'gary' }, ] const user = users.find(user => user.id === '6gbe') console.log(user)
لذلك ، استخدم طريقة
filter
عندما تريد تصفية المصفوفة
بالكامل ، وطريقة
find
عندما تكون متأكدًا من أنك تبحث عن عنصر
فريد في المصفوفة.
findIndexهذه الطريقة هي نفس طريقة
find
، لكنها تُرجع فهرس العنصر الأول الموجود بدلاً من العنصر نفسه.
const users = [ { id: 'af35', name: 'john' }, { id: '6gbe', name: 'mary' }, { id: '932j', name: 'gary' }, ] const user = users.findIndex(user => user.id === '6gbe') console.log(user)
قد تعتقد أن
findIndex
و
indexOf
هما نفس الشيء. ليس حقا المعلمة الأولى لـ
indexOf
هي قيمة أولية (قيمة منطقية أو رقم أو سلسلة أو قيمة أو حرف غير محدد) ، في حين أن المعلمة الأولى
findIndex
هي وظيفة رد اتصال.
لذلك ، عندما تحتاج إلى العثور على فهرس عنصر في صفيف من القيم البدائية ، يمكنك العمل مع
indexOf
. إذا كان لديك عناصر أكثر تعقيدًا ، مثل الكائنات ، فاستخدم
findIndex
.
شريحةعندما تحتاج إلى المشاركة في صفيف أو نسخ صفيف ، يمكنك الرجوع إلى طريقة
slice
. لكن كن حذرًا: مثل عامل الانتشار ، تقوم
slice
بإرجاع
نسخة ضحلة .
const numbers = [1, 2, 3, 4, 5] const copy = numbers.slice()
في بداية المقال ، ذكرت أن الحلقات غالبًا ما تكون عديمة الفائدة. دعني أريك كيف تتخلص منها.
افترض أنك تريد إرجاع عدد معين من رسائل الدردشة من واجهة برمجة التطبيقات وتحتاج فقط إلى رؤية خمس منها. فيما يلي طريقتان: واحدة مع حلقات ، والآخر مع طريقة
slice
.
بعضإذا كنت تريد التحقق مما إذا كان
هناك عنصر واحد على الأقل من المصفوفة يجتاز الاختبار ، يمكنك استخدام
some
العناصر . مثل
map
، أو
filter
أو
find
، تأخذ
some
الطرق وظيفة رد الاتصال باعتبارها المعلمة الوحيدة ، ثم ترجع
true
إذا نجح عنصر واحد على الأقل في التحقق ،
false
إن لم يكن.
some
مناسب أيضًا للعمل مع الأذونات.
const users = [ { id: 'fe34', permissions: ['read', 'write'], }, { id: 'a198', permissions: [], }, { id: '18aa', permissions: ['delete', 'read', 'write'], } ] const hasDeletePermission = users.some(user => user.permissions.includes('delete') ) console.log(hasDeletePermission)
كلتشبه هذه الطريقة
some
، إلا أنها تتحقق من تطابق
كل عنصر (
وليس عنصر ) مع الشرط.
const users = [ { id: 'fe34', permissions: ['read', 'write'], }, { id: 'a198', permissions: [], }, { id: '18aa', permissions: ['delete', 'read', 'write'], } ] const hasAllReadPermission = users.every(user => user.permissions.includes('read') ) console.log(hasAllReadPermission)
شقة (ES2019)هذه طرق جديدة تمامًا في عالم JavaScript. عادةً ما تقوم
flat
بإنشاء صفيف جديد يربط جميع عناصر الصفيف المتداخل. يتطلب الأمر معلمة واحدة - رقم يشير إلى مقدار ما تريده لتقليل بُعد المصفوفة.
const numbers = [1, 2, [3, 4, [5, [6, 7]], [[[[8]]]]]] const numbersflattenOnce = numbers.flat() console.log(numbersflattenOnce)
flatMap (ES2019)خمن ماذا هذه الطريقة؟ أراهن أنك سوف تفهم اسم واحد.
أولاً ، يتم تشغيل وظيفة التعيين لكل عنصر ، ثم تقليص الصفيف في وقت واحد. بهذه البساطة!
const sentences = [ 'This is a sentence', 'This is another sentence', "I can't find any original phrases", ] const allWords = sentences.flatMap(sentence => sentence.split(' ')) console.log(allWords)
في هذا المثال ، لديك العديد من الجمل في الصفيف وتريد الحصول على جميع الكلمات. بدلاً من استخدام طريقة
map
وتقسيم جميع الجمل إلى كلمات ثم تقصير المصفوفة ، يمكنك استخدام
flatMap
.
ثم يمكنك حساب عدد الكلمات باستخدام وظيفة
flatMap
(لا ينطبق هذا على
flatMap
، أريد فقط أن
flatMap
لك مثالًا آخر لاستخدام طريقة
flatMap
).
const wordsCount = allWords.reduce((count, word) => { count[word] = count[word] ? count[word] + 1 : 1 return count }, {}) console.log(wordsCount)
وغالبا ما تستخدم طريقة
flatMap
في البرمجة التفاعلية. يمكنك أن ترى مثالا
هنا .
انضمإذا كنت بحاجة إلى إنشاء سلسلة بناءً على عناصر الصفيف ، فإن طريقة الصلة هي ما تحتاجه. يسمح لك بإنشاء خط جديد عن طريق توصيل جميع عناصر المصفوفة ، مفصولة بفاصل المقدمة.
على سبيل المثال ، باستخدام الصلة
join
يمكنك عرض جميع المشاركين بصريًا في أي نشاط.
const participants = ['john', 'mary', 'gary'] const participantsFormatted = participants.join(', ') console.log(participantsFormatted)
وهذا مثال أكثر واقعية حيث يمكنك أولاً تصفية المشاركين والحصول على أسمائهم.
const potentialParticipants = [ { id: 'k38i', name: 'john', age: 17 }, { id: 'baf3', name: 'mary', age: 13 }, { id: 'a111', name: 'gary', age: 24 }, { id: 'fx34', name: 'emma', age: 34 }, ] const participantsFormatted = potentialParticipants .filter(user => user.age > 18) .map(user => user.name) .join(', ') console.log(participantsFormatted)
منهذه طريقة
ثابتة تنشئ صفيفًا جديدًا من كائن يشبه الصفيف أو يمكن تكراره ، مثل سلسلة. يمكن أن يكون مفيدًا عند العمل مع طراز كائن المستند.
const nodes = document.querySelectorAll('.todo-item')
هل رأيت أننا استخدمنا نوع صفيف بدلاً من مثيل صفيف؟ هذا هو السبب في أن هذه الطريقة تسمى ساكنة.
ثم يمكنك الاستمتاع بالعُقد ، على سبيل المثال تسجيل مستمعي الأحداث لكل منهم باستخدام طريقة
forEach
.
todoItems.forEach(item => { item.addEventListener('click', function() { alert(`You clicked on ${item.innerHTML}`) }) })
صفيف تعديل يستحق معرفة حول
فيما يلي طرق قياسية أخرى. الاختلاف هو أنها تعدل الصفيف الأصلي. لا حرج في التغيير ، لكن يجب أن تفكر في ذلك عند العمل.
إذا كنت لا ترغب في تعديل الصفيف الأصلي أثناء العمل مع هذه الطرق ، فقم بعمل نسخة مسبقة من السطح أو كاملة.
const arr = [1, 2, 3, 4, 5] const copy = [...arr]
نوعنعم ،
sort
يعدل الصفيف الأصلي. في الواقع ، يفرز عناصر المصفوفة في مكانها. تقوم طريقة الفرز الافتراضية بتحويل جميع العناصر إلى سلاسل وترتيبها بترتيب أبجدي.
const names = ['john', 'mary', 'gary', 'anna'] names.sort() console.log(names)
كن حذرًا: إذا انتقلت ، على سبيل المثال ، من Python ، فإن طريقة
sort
عند العمل مع مجموعة من الأرقام لن تمنحك النتيجة المرجوة.
const numbers = [23, 12, 17, 187, 3, 90] numbers.sort() console.log(numbers)
كيف ثم لفرز مجموعة؟ طريقة
sort
تأخذ وظيفة واحدة -
وظيفة المقارنة . يستغرق معلمتين: العنصر الأول (
) والعنصر الثاني للمقارنة (
b
). تتطلب المقارنة بين هذين العنصرين إعادة الرقم:
- إذا كانت القيمة سالبة -
a
فرز b
قبل b
؛ - إذا كانت القيمة موجبة ،
b
فرز b
قبل - إذا كانت القيمة 0 ، لا تغيير.
ثم يمكنك فرز الأرقام.
const numbers = [23, 12, 17, 187, 3, 90] numbers.sort((a, b) => a - b) console.log(numbers)
أو يمكنك فرز التواريخ من الأحدث.
const posts = [ { title: 'Create a Discord bot under 15 minutes', date: new Date(2018, 11, 26), }, { title: 'How to get better at writing CSS', date: new Date(2018, 06, 17) }, { title: 'JavaScript arrays', date: new Date() }, ] posts.sort((a, b) => a.date - b.date)
التعبئةتقوم طريقة
fill
بتعديل أو تعبئة كل عناصر الصفيف من فهرس البداية إلى النهاية بالقيمة المحددة. مثال على الاستخدام الممتاز
fill
هو تعبئة صفيف جديد بالبيانات الأولية.
عكسيبدو لي أن اسم الأسلوب يشرح جوهره بالكامل.
const numbers = [1, 2, 3, 4, 5] numbers.reverse() console.log(numbers)
البوبهذا الأسلوب يزيل العنصر الأخير من الصفيف ويعيده.
const messages = ['Hello', 'Hey', 'How are you?', "I'm fine"] const lastMessage = messages.pop() console.log(messages)
الطرق التي يمكن استبدالها
في القسم الأخير ، ستجد طرقًا لتعديل المصفوفة الأصلية والتي يسهل العثور عليها. أنا لا أقول أنهم بحاجة إلى تخفيض ، أريد فقط أن أنقل إليكم أن بعض الطرق لها آثار جانبية ويمكن استبدالها.
دفعهذه الطريقة تستخدم بشكل متكرر. يسمح لك بإضافة عنصر واحد أو أكثر إلى الصفيف ، وكذلك إنشاء صفيف جديد بناءً على العنصر السابق.
const todoItems = [1, 2, 3, 4, 5] const itemsIncremented = [] for (let i = 0; i < items.length; i++) { itemsIncremented.push(items[i] + 1) } console.log(itemsIncremented)
إذا كنت بحاجة إلى إنشاء صفيف على أساس آخر ، كما هو الحال في طريقة
itemsIncremented
، فهناك
map
مناسبة أو
filter
أو
reduce
itemsIncremented
المألوفة لدينا بالفعل. على سبيل المثال ، يمكننا أن نأخذ
map
للقيام بذلك.
const itemsIncremented = todoItems.map(x => x + 1)
وإذا كنت تريد استخدام
push
عندما تحتاج إلى إضافة عنصر جديد ، فسيكون مشغل السبريد مفيدًا.
const todos = ['Write an article', 'Proofreading'] console.log([...todos, 'Publish the article'])
لصقغالبًا ما
splice
الوصول إلى
splice
لتنظيف عنصر في فهرس معين. يمكنك أن تفعل الشيء نفسه مع طريقة
filter
.
const months = ['January', 'February', 'March', 'April', ' May']
قد تسأل: ماذا لو كنت بحاجة لإزالة الكثير من العناصر؟ ثم استخدم
slice
.
const months = ['January', 'February', 'March', 'April', ' May']
تغيرتعمل طريقة
shift
إزالة العنصر الأول للصفيف وإعادته. للقيام بذلك بأسلوب البرمجة الوظيفية ، يمكنك استخدام بيان الحيز أو الاستراحة.
const numbers = [1, 2, 3, 4, 5]
unshiftتسمح لك طريقة unshift بإضافة عنصر واحد أو أكثر إلى بداية صفيف. مثل
shift
، يمكنك القيام بذلك مع عامل الانتشار.
const numbers = [3, 4, 5]
TL ؛ د
- عندما تريد إجراء بعض العمليات باستخدام صفيف ، لا تستخدم حلقة for ولا تعيد اختراع العجلة ، لأنه على الأرجح هناك طريقة من أعلاه يمكنها القيام بما تحتاجه.
- غالبًا ما تستخدم
map
filter
reduce
الطرق ومشغل الانتشار - هذه أدوات مهمة لأي مطور. - هناك أيضًا العديد من أساليب الصفيف التي سيكون من الجيد معرفتها:
slice
، some
، flatMap
، وما إلى ذلك. تعرف عليها وتطبق إذا لزم الأمر. - الآثار الجانبية يمكن أن تؤدي إلى تغييرات غير مرغوب فيها. ضع في اعتبارك أن بعض الأساليب تعدل الصفيف الأصلي.
- طريقة
slice
ومشغل انتشار عمل نسخ ضحلة. نتيجة لذلك ، سيكون للأجسام والهيئات الفرعية نفس الروابط - وهذا أمر يستحق الانتباه أيضًا. - يمكن استبدال الطرق القديمة التي تقوم بتعديل الصفيف بطرق جديدة. عليك أن تقرر ما يجب القيام به.
أنت الآن تعرف كل شيء يجب أن تعرفه عن صفيف JavaScript. إذا أعجبك
هذا المقال ، فانقر على زر "Pat" (حتى 50 مرة ، إذا كنت تريد :-)) وشاركه. ولا تتردد في مشاركة انطباعاتك في التعليقات!