A while ago, I gave a PowerPoint knowledge share presentation to a group of fellow C# developers at my office on JavaScript array methods and how they compare to the .NET LINQ methods that we’re familiar with.
I’ve found myself referencing that presentation since then, so I thought I’d put it somewhere accessible to me and others for future reference.
The headings below are links to the MDN documentation for the methods, so you can find more details and browser compatibility information there.
(These are not all of the many array methods, just the “LINQ-y” ones.)
array.length
- purpose: get array size
- returns: number
- LINQ equivalent: IEnumerable<T>.Count (or Array.Length)
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
console.log(`There are ${months.length} months in your earth year`);
There are 12 months in your earth year
array.forEach
- purpose: do something with each item in array
- arguments: item, (index), (list)
- “callback” responsibility: do something with item
- returns: nothing (undefined)
- C#/LINQ equivalent: List<T>.ForEach
const year = new Date().getFullYear();
const getDaysInMonth = month =>
new Date(year, new Date(`1-${month}-${year}`).getMonth() + 1, 0).getDate();
months.forEach(m => console.log(`${m} has ${getDaysInMonth(m)} days in ${year}`));
Jan has 31 days in 2019
Feb has 28 days in 2019
Mar has 31 days in 2019
Apr has 30 days in 2019
May has 31 days in 2019
Jun has 30 days in 2019
Jul has 31 days in 2019
Aug has 31 days in 2019
Sep has 30 days in 2019
Oct has 31 days in 2019
Nov has 30 days in 2019
Dec has 31 days in 2019
forEach and many of the other functions discussed below require an “item” argument, but also accept optional “index” and “list” arguments.
Here’s an example of forEach(item, index):
months.forEach((m, i) => console.log(`${m} is month #${i + 1}`));
Jan is month #1
Feb is month #2
Mar is month #3
Apr is month #4
May is month #5
Jun is month #6
Jul is month #7
Aug is month #8
Sep is month #9
Oct is month #10
Nov is month #11
Dec is month #12
…and forEach(item, index, list):
months.forEach((m, i, list) => console.log(`${i + 1}) ${m} follows ${list.slice(0, i)}`));
1) Jan follows
2) Feb follows Jan
3) Mar follows Jan,Feb
4) Apr follows Jan,Feb,Mar
5) May follows Jan,Feb,Mar,Apr
6) Jun follows Jan,Feb,Mar,Apr,May
7) Jul follows Jan,Feb,Mar,Apr,May,Jun
8) Aug follows Jan,Feb,Mar,Apr,May,Jun,Jul
9) Sep follows Jan,Feb,Mar,Apr,May,Jun,Jul,Aug
10) Oct follows Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep
11) Nov follows Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct
12) Dec follows Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov
I’ll only show fn(item) examples for the remaining functions…
array.map
- purpose: map array into a new array (of same or different types)
- arguments: item, (index), (list)
- “callback” responsibility: return new item for the new array
- returns: new array
- LINQ equivalent: IEnumerable<T>.Select
const firstDaysOfMonths = months.map(m => new Date(`1-${m}-${year}`));
firstDaysOfMonths.forEach(item => console.log(item));
Mon Jan 01 2018 00:00:00 GMT-0600 (Central Standard Time)
Thu Feb 01 2018 00:00:00 GMT-0600 (Central Standard Time)
Thu Mar 01 2018 00:00:00 GMT-0600 (Central Standard Time)
Sun Apr 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Tue May 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Fri Jun 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Sun Jul 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Wed Aug 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Sat Sep 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Mon Oct 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Thu Nov 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Sat Dec 01 2018 00:00:00 GMT-0600 (Central Standard Time)
array.filter
- purpose: create a new array of items that match a predicate
- arguments: item, (index), (list)
- “callback” responsibility: predicate — return “truthy/falsy” value for item
- returns: new filtered array
- LINQ equivalent: IEnumerable<T>.Where
const monthsWith30Days = months.filter(m => getDaysInMonth(m) === 30);
console.log(monthsWith30Days);
Apr,Jun,Sep,Nov
array.reduce
- purpose: determine something (e.g. sum, highest value) based on array items
- arguments: result, item, (index), (list)
- “callback” responsibility: based on previous result, what should be passed to next iteration?
- returns: result of last iteration
- LINQ equivalent: kind of like IEnumerable.Aggregate<T>
const daysInYear = months.reduce((result, m) => result + getDaysInMonth(m), /*initial value:*/ 0);
console.log(`There are ${daysInYear} days in ${year}`);
There are 365 days in 2018
array.reduceRight
…is like reduce, but it processes items from “right to left”. When I originally presented this material, I couldn’t think of a good use for reduceRight, but I saw an egghead.io Build Complex Functions with Function Composition in JavaScript lesson by Kyle Shevlin that showed a nifty use for it:
const shout = message => message.toUpperCase();
const exclaim = message => message + '!';
const repeat = message => `${message} ${message}`;
console.log(shout(repeat(exclaim('nested functions'))));
const compose = (...funcs) => x => funcs.reduceRight((result, func) => func(result), x);
const makeKnown = compose(
shout,
repeat,
exclaim
);
console.log(makeKnown('composed function'));
NESTED FUNCTIONS! NESTED FUNCTIONS!
COMPOSED FUNCTION! COMPOSED FUNCTION!
array.some
- purpose: Does one or more item match a predicate?
- arguments: item, (index), (list)
- “callback” responsibility: predicate — return “truthy/falsy” value for item
- returns: true if any “truthy” responses (stops iterating after first “truthy” response)
- LINQ equivalent: IEnumerable<T>.Any
const hasMonthStartingWithA = months.some(m => {
console.log(`checking ${m}...`);
return m[0] === 'A';
});
console.log(hasMonthStartingWithA);
checking Jan...
checking Feb...
checking Mar...
checking Apr...
true
array.every
- purpose: Do all items match a predicate?
- arguments: item, (index), (list)
- “callback” responsibility: predicate — return “truthy/falsy” value for item
- returns: true if all responses are “truthy” (stops iterating after “falsy” response)
- LINQ equivalent: IEnumerable<T>.All
const hasNo30DayMonths = months.every(m => {
const daysInMonth = getDaysInMonth(m);
console.log(`${m} has ${daysInMonth} days`);
return daysInMonth != 30;
});
console.log(hasNo30DayMonths);
Jan has 31 days
Feb has 28 days
Mar has 31 days
Apr has 30 days
false
array.find
- purpose: find first item matching a predicate
- arguments: item, (index), (list)
- “callback” responsibility: predicate — return “truthy/falsy” value for item
- returns first “truthy” item (or undefined, if none found — stops iterating after first “truthy response)
- LINQ equivalent: IEnumerable<T>.FirstOrDefault
const first30DayMonth = months.find(m => getDaysInMonth(m) === 30);
const first40DayMonth = months.find(m => getDaysInMonth(m) === 40);
console.log(`1st 30 day month: ${first30DayMonth}`);
console.log(`1st 40 day month: ${first40DayMonth}`);
1st 30 day month: Apr
1st 40 day month: undefined
array.findIndex
…is like find, but it returns the found index instead of the item (-1 if not found):
const index30 = months.findIndex(m => getDaysInMonth(m) === 30);
const index40 = months.findIndex(m => getDaysInMonth(m) === 40);
console.log(`1st 30 day index: ${index30}`);
console.log(`1st 40 day index: ${index40}`);
1st 30 day index: 3
1st 40 day index: -1
array.includes
- purpose: does array include specified entry?
- returns: bool
- LINQ equivalent: IEnumerable<T>.Contains
console.log(months.includes('Aug'));
console.log(months.includes('Dog'));
true
false
array.sort
- purpose: sort array items
-
arguments: (compareFunction) — optional callback function that takes item1 and item2 and returns:
- a negative number if item1 > item2
- zero if item1 == item2
- a positive number if item2 > item1
(If compareFunction is omitted, a unicode comparison is performed, meaning everything is treated like a string)
returns: the sorted array (not a new sorted array — it mutates the source array!) LINQ equivalent: IEnumerable<T>.OrderBy
This is an older JavaScript function, from back when there were fewer “good parts”.
Notice that the months.sort() call updates the contents of the months variable:
console.log(months);
console.log(months.sort());
console.log(months);
Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
Apr,Aug,Dec,Feb,Jan,Jul,Jun,Mar,May,Nov,Oct,Sep
Apr,Aug,Dec,Feb,Jan,Jul,Jun,Mar,May,Nov,Oct,Sep
…and that without a compareFunction, numbers are sorted like strings:
console.log(['1', '5', '10', '15', '20'].sort());
console.log([1, 5, 10, 15, 20].sort());
1,10,15,20,5
1,10,15,20,5
If you need to create a new sorted array and leave the original array unsorted, you can first clone the array via the “slice” function or the spread (“…”) operator:
console.log(months);
console.log(months.slice().sort());
console.log([...months].sort());
console.log(months);
Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
Apr,Aug,Dec,Feb,Jan,Jul,Jun,Mar,May,Nov,Oct,Sep
Apr,Aug,Dec,Feb,Jan,Jul,Jun,Mar,May,Nov,Oct,Sep
Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
Here are examples of the sort method with a compareFunction callback:
const sortedNumbers = [1, 5, 10, 15, 20].sort((num1, num2) => num1 - num2);
console.log(sortedNumbers);
const sortedByDaysInMonth = months.sort((m1, m2) => getDaysInMonth(m1) - getDaysInMonth(m2));
console.log(sortedByDaysInMonth);
1,5,10,15,20
Feb,Jun,Sep,Apr,Nov,Jul,Dec,Jan,Mar,Oct,May,Aug
array.concat
- purpose: merge two arrays into a new array
- returns: new array
- LINQ equivalent: IEnumerable<T>.Union
const months1 = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
const months2 = ['Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const months = months1.concat(months2);
console.log(months);
Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
Top comments (0)