رمزگشایی روش های آرایه – انجمن DEV

به نوعی، به نوعی، مردم فکر می کنند for
درک و درک حلقه ها آسان تر است… من اینجا هستم تا آن را تغییر دهم.
من از جاوا اسکریپت استفاده خواهم کرد، اما بیشتر زبانها روشها را به روشی دیگر پیادهسازی میکنند، گاهی اوقات با کمی تفاوت در نامگذاری.
مبانی
اکثر روش ها، به استثنای موارد، دارای امضای یکسان هستند.
بیایید با آن مقایسه کنیم for
حلقه ها:
const array = ['a', 'b', 'c'];
// the classic `for` loop you can have better
// control over the indexed you're using
for (let index = 0; index < array.length; index++) {
const element = array[index];
console.log(element); // a, b, c
}
// the `for in` gives the index
for (const index in array) {
const element = array[index];
console.log(element); // a, b, c
}
// the `for of` gives the element
for (const element of array) {
console.log(element); // a, b, c
}
- عنصر – معمولاً این تنها چیزی است که واقعاً نیاز دارید
- index – کاربردهایی برای استفاده از ایندکس وجود دارد
- آرایه – هنگام زنجیر کردن متدها، این به شما امکان می دهد از مقادیر فعلی در مرحله ای که در آن هستید استفاده کنید.
دو چیز را باید به خاطر بسپارید:
- از بهترین روش برای کاری که انجام می دهید استفاده کنید
اگر نیازی به بازگرداندن چیزی ندارید، از a map
این بازگشت باعث می شود فکر کنم شما فراموش کرده اید چیزی را برگردانید.
به همین ترتیب، راههای دوربرگردان زیادی وجود دارد که وضعیت فعلی زبان راههای بهتری برای انجام آنها دارد، مانند استفاده از findIndex !== -1
وقتی یک some
همین کار را خواهد کرد.
تا زمانی که چیزی که برمی گردانید آرایه دیگری باشد، می توانید کاری انجام دهید و آن را به مرحله بعدی منتقل کنید.
گاهی اوقات این منطقی است، اما گاهی اوقات، ممکن است بخواهید آنها را به متغیرهای توصیفی اختصاص دهید.
برای هر
“برای هر عنصر” در آرایه، کاری انجام می دهد و چیزی بر نمی گرداند.
['a', 'b', 'c'].forEach((element) => {
// console.log doesn't return anything
// so it's perfect for the forEach
console.log(element); // a, b, c
})
شما زمانی از آن استفاده می کنید که فقط نیاز به انجام کاری دارید و چیزی را پس نمی دهید: سیاهه ها، نان تست…
درک و استفاده از آن آسان است، اما از آنجایی که چیزی را بر نمی گرداند، واقعاً کاربردهای زیادی وجود ندارد. (روش های بهتری برای هر چیزی که فکر می کنید وجود دارد)
نقشه
فرزند پوستر متدهای آرایه!
برای هر عنصر در آرایه، یک مقدار برمی گرداند.
(توجه: حتی اگر برنگردید باز می گردد undefined
)
// not adding {} in the arrow function, means it returns implicitly
[1, 2, 3].map(element => element * 2); // result array is [2, 4, 6]
[1, 2, 3].map(element => {
if(element % 2 !== 0) { // remainder of the division by 2 not equal to zero
return element * 2;
}
// no "else" returns
}) // resulting array [2, undefined, 6]
از آنجایی که آرایه ای با همان اندازه را برمی گرداند، می توان از آن برای چندین چیز استفاده کرد و زنجیره سازی را آسان می کند.
كاهش دادن
آفت مردمی که روشها را یاد میگیرند… اما واقعاً آنقدرها هم پیچیده نیست.
برای هر عنصر در آرایه، “یک” چیز را برمی گرداند (که می تواند هر چیزی باشد).
به صورت اختیاری، می توانید یک مقدار شروع داشته باشید.
// classical use case
[1, 2, 3].reduce((accumulator, element) => accumulator + element, 0); // returns 6
// classical mistake nr 1: not returning anything
[1, 2, 3].reduce((accumulator, element) => {
console.log(accumulator); // 0 (initial value), undefined, undefined (undefined because you didn't return)
console.log(element); // 1, 2, 3
accumulator + element; // this would be 1 (0 + 1), then NaN, NaN (number + undefined/NaN)
// always remember to return something, even if only the accumulator
}, 0);
// (possible) mistake: not having an initial value
// no initial value means the first element is the initial value
[1, 2, 3].reduce((accumulator, element)=> accumulator + element); // retuns 6
[].reduce((accumulator, element)=> accumulator + element); // throws because empty array with no initial value
// things start to be different for more complex use cases
[1, 2, 3].reduce((accumulator, element)=>{
if (element % 2 === 0) {
accumulator.even.push(element);
} else {
accumulator.odd.push(element);
}
return accumulator;
// below I'm using JSDoc to type the initial value
// because using JS doesn't mean not using types ;]
}, /** @type {{ even: number[], odd: number[] }} */ ({ even: [], odd: []}));
// this returns: { even: [ 2 ], odd: [ 1, 3 ] }
// Not using an initial value will break this in multiple ways.
// this is another way to write the same thing
[1, 2, 3].reduce((accumulator, element)=>{
if (element % 2 === 0) {
return {
...accumulator,
even: accumulator.even.concat(element),
}
}
return {
...accumulator,
odd: accumulator.odd.concat(element),
}
}, /** @type {{ even: number[], odd: number[] }} */({ even: [], odd: []}));
// the important thing to remember is to always return something
// the "one" thing it returns can be anything:
[1, 2, 3].reduce((accumulator, element) => {
if (element % 2 === 0) {
accumulator[1] += element;
} else {
accumulator[0] += element;
}
return accumulator;
}, /** @type {[number, number]} [*/([0, 0]));
// this returns [4, 2]
// and would again have multiple problems without an initial value
اگر میخواهید یک یا چند متغیر را در خارج نمونهسازی کنید، از a استفاده کنید for
حلقه یا حتی یک forEach
و آن را جهش دهید، سپس یک مورد استفاده برای آن است reduce
.
همیشه یک چیز را برمی گرداند، و همانطور که می بینید می تواند هر چیزی باشد: عدد، رشته، آرایه، شی…
در حالی که، شما اساساً می توانید هر کاری را با آن انجام دهید reduce
، بررسی کنید که آیا روش دیگری وجود ندارد که این مورد را بهتر پوشش دهد.
یک نیز وجود دارد reduceRight
این همان چیزی است، اما از آخرین عنصر شروع می شود.
فیلتر کنید
برای هر عنصر در آرایه، آرایه ای را برمی گرداند که می تواند اندازه کوچکتری داشته باشد.
در حالی که reduce
یک چیز را برمی گرداند، filter
همیشه آرایه ای را برمی گرداند که می تواند از خالی به همان اندازه ورودی باشد.
[1, 2, 3].filter(element => element % 2 !== 0); // returns [1, 3]
[1, 2, 3].filter(element => element % 5 === 0); // return [0]
// one common use case: remove falsy values
[1, 2, 3].map(element => {
if (element % 2 !== 0) {
return element;
}
}) // at this point you would have: [1, undefined, 3]
.filter(Boolean); // after this return [1, 3]
اگر می خواهید مقادیر را از یک آرایه حذف کنید، filter
روشی است که شما می خواهید
و برای کسانی که نمی دانستند: filter(Boolean)
روشی زیبا برای حذف مقادیر نادرست است.
باید مراقب باشید که مقادیر نادرست مانند را حذف کند ''
(رشته خالی) و 0
(صفر).
مسطح و مسطح نقشه
صاف کردن یک آرایه چیزی نیست که هر روز از آن استفاده کنید، اما مطمئناً در بسیاری از موارد مفید است. اساساً به flat
حذف ابعاد از یک آرایه است.
اگر ماتریس 2×2 دارید: [[1, 1], [1, 1]]
و شما آن را صاف می کنید، در نهایت با یک آرایه 4 آیتم ساده مواجه می شوید: [1, 1, 1, 1]
.
[1, 2, 3].map(element => {
return [[[element]]]; // sometimes you return values/tuples
// depending on what you really wanted to return, you just need to flat it
}) // here would return [[[[1]]],[[[2]]],[[[3]]]]
.flat(1) // returns [[[1]],[[2]],[[3]]]
.flat(2); // returns [1, 2, 3]
[1, 2, 3].map(element => {
return [[[element]]];
}) // here would return [[[[1]]],[[[2]]],[[[3]]]]
.flat(Infinity); // returns [1, 2, 3]
// flatting to infinity means it will remove all dimensions
شما تماس بگیرید flat
از یک آرایه و عددی را می گیرد که تعداد ابعاد را از آن جدا می کنید. اگر می خواهید یک آرایه ساده به عنوان نتیجه داشته باشید، مهم نیست که آرایه چقدر ابعاد دارد، از آن استفاده کنید flat(Infinity)
همانطور که این کار را انجام خواهد داد.
[1, 2, 3].flatMap(element => {
return [element * 2]; // returns [2], [4], [6]
}); // returns [2, 4, 6] because it flattened
[1, 2, 3].flatMap(element => {
if (element % 2 === 0) {
return element * 2; // return 4
}
// without returning anything, it would result in [undefined, 4, undefined]
// while flatMap doesn't remove falsy values
// a flattened empty array disappear
return [];
}); // returns [4]
flatMap
اساسا یک است map
به دنبال flat(1)
.
TIL: می توانید استفاده کنید flatMap
و برگشت []
برای مقادیر نادرست فقط مقادیر را برمی گرداند
برخی و هر
آنها موارد سرگرم کننده ای هستند که پس از یادگیری در مورد شما موارد استفاده را در همه جا پیدا خواهید کرد!
معمولاً مورد استفاده به صورت زیر است: filter(/* for something */).length /* (not) equal to something */
یا Boolean(find(/* something (not) equal */))
.
برای هر عنصر در آرایه، some
اگر حداقل یکی از گزاره عبور کند true برمی گرداند، every
اگر همه از آن عبور کنند
[1, 2, 3].some(element => element % 2 === 0); // true
[1, 2, 3].every(element => element % 2 === 0); // false
یک چیز جالب این است که هر دو زودتر برمی گردند، some
در اول truthy
ارزش بازگشتی و every
در اول falsy
مقدار بازگشتی
هنگامی که تنها چیزی که نیاز دارید یک بولی از اگر چیزی وجود دارد یا نه است، از هر کدام استفاده کنید some
یا every
.
پیدا کردن و پیدا کردن ایندکس
find
اولین عنصری را که از گزاره یا عبور می کند برمی گرداند undefined
در غیر این صورت، findIndex
ایندکس عنصر یا را برمی گرداند -1
در غیر این صورت.
هر دو از فهرست شروع به جستجو می کنند 0
، اما اگر آخرین مورد را می خواهید، از تغییرات “آخرین” استفاده کنید.
// returns the element:
[1, 2, 3].find(element => element % 2 !== 0); // 1
[1, 2, 3].findLast(element => element % 2 !== 0); // 3
// return the index:
[1, 2, 3].findIndex(element => element % 2 !== 0); // 0
[1, 2, 3].findLastIndex(element => element % 2 !== 0); // 2
شامل می شود
گاهی اوقات شما فقط می خواهید بررسی کنید که آیا مقداری در یک آرایه وجود دارد یا خیر، این کار برابری عمیق را بررسی می کند.
[1, 2, 3].includes(1); // true
[1, 2, 3].includes('1'); // false
به احتمال زیاد، ما می توانیم در اینجا وارد کنیم indexOf
و lastIndexOf
هر دو یک مقدار را بررسی می کنند، اما شاخص یا را برمی گرداند -1
در غیر این صورت.
[1, 0, 1].indexOf(1); // 0
[1, 0, 1].indexOf('1'); // -1
[1, 0, 1].lastIndexOf(1); // 2
[1, 0, 1].lastIndexOf('1'); // -1
مورد استفاده برای includes
در این میان معمولاً در حال جستجوی آرایه ای از مقادیر اولیه (رشته، عدد، نمادها…) است. some
و every
برای چیزهای پیچیده تر از اینکه مقدار وجود دارد یا نه یا برای اشیا استفاده می شود.
آخرین اظهارات
اسناد MDN به همان اندازه که می آیند خوب هستند. ممکن است ندانید که همه آنها وجود دارند، اما زمانی که متوجه شوید آنها کاملاً ساده هستند.
سپس، ممکن است برخی از افراد بدانند که روش ها وجود دارد، اما نحوه به کارگیری آنها را ندانند. بنابراین، اگر می خواهید، نمونه هایی را بفرستید که نمی دانید چگونه روش ها را اعمال کنید و من می توانم گزینه ها را اصلاح کنم.