Using Array hidden useful methods

While writhing JS, we use array very often. We have to use array to handle multiple elements in order, because plain objects don’t guarantee the order of its elements on the specification.

In this article, I’d summarize some Array methods, defined since ES5 or after, which are useful but they’re not well known.

About a difference between Array.method and Array.prototype.method
Array.method is a ‘Class Method’, and Array.prototype.method is a ‘Instance Method’. Class methods can’t be called via each arrays directly, then they must be called by Array.method. Instance methods can be called via each arrays, like [1, 2, 3].method.

Array.from()

It is a new methods to create an array. The main usage is to convert Array-Like objects to array.

You can call this method with passing a callback function to convert each elements as you wish like Array.prototype.map().

const divs = document.querySelectorAll('div')

/* Before */

// processing elements by using for...
var arr = []
for (var i = 0; i < divs.length; i++) {
  arr.push(divs[i])
}

// diverting Array methods with call/apply...
Array.prototype.forEach.call(divs, function (div) {
  // ...
})

/* After */

const divsArray = Array.from(divs)
// an array of div elements
const divsTextArray = Array.from(divs, div => div.textContent)
// an array of texts of divs

Array.prototype.every()

This method turns array elements one by one, and returns true if all the elements passed the given conditions by a callback function, otherwise false.

For example, there is an array which is containing 5 test scores, and if either score is under 30, the student has to undergo supplementation. You can judge it via this method easily.

const A = [68, 45, 90, 82, 51]
const B = [73, 100, 87, 27, 96]

/* Before */

var isFailing = false
for (var i = 0; i < A.length; i++) {
  if (A[i] < 30) {
    isFailing = true
    break;
  }
}

/* After */

A.every(score => score >= 30)
// false
B.every(score => score >= 30)
// true

Array.prototype.some()

This method will return true if an element at least passed the test by a callback function, otherwise false.

It’s an opposite method of every(). When you set an opposite condition, this method will return the same result of every().

const A = [68, 45, 90, 82, 51]
const B = [73, 100, 87, 27, 96]

A.some(score => score < 30)
// false
B.some(score => score < 30)
// true

Array.prototype.includes()

This method checks whether the array has the element and returns true or false.

It has been possible to check it by Array.prototype.indexOf(). But this method can make the code a bit more short.

const array = ['a', 'c', 'f', 'b', 'e', 'd']

/* Before */

array.indexOf('c') !== -1
// true
array.indexOf('g') !== -1
// false

/* After */

array.includes('c')
// true
array.includes('g')
// false

Since we can capture the meaning of the word ‘include’, it’s easier to understand to read than indexOf().

Array.prototype.findIndex()

This methods will search an element from an array and return the index of the element if find, otherwise -1.

It’s very similar to indexOf(), but findIndex() receives a condition as a callback function. Then, this method can be used for plain objects.

const array = [
  { a: 1 },
  { a: 2 },
  { a: 3 },
  { a: 4 },
  { a: 5 }
]

array.indexOf({ a: 4 })
// -1
array.findIndex(obj => obj.a === 4)
// 3

With indexOf(), you can get the index even if they have same properties and values absolutely, since they are indeed another objects, so -1 was returned finally.

When you want to search an element by converting Array-Like objects to array for instance, you should choose findIndex() or find().

Array.prototype.find()

Although findIndex() is a method to get an index, find() returns the element itself.

const array = [
  { a: 1 },
  { a: 2 },
  { a: 3 },
  { a: 4 },
  { a: 5 }
]

array.find(obj => obj.a === 4)
// { a: 4 }

Array.prototype.reduce()

This method processes each elements of an array once. It’s similar to forEach(), but this method can take over the previous result to next element’s process.

const array = [1, 2, 3, 4, 5]

let total_forEach = 0
array.forEach(num => {
  total_forEach += num
})

const total_reduce = array.reduce((prev, current) => prev + current)

console.log(total_forEach)  // 15
console.log(total_reduce)   // 15

In addition, this method has the feature that the returned value in the callback function will be taken over to the next callback execution. Then reduce() can be used to process element with previous/next element.

What I was most indebted is a serialization of Promise. It can be written shortly with reduce to chain Promise. As start next Promise with previous Promise finishing.

const urls = [
  'url1',
  'url2',
  'url3',
  'url4',
  'url5'
]

urls.map(url => () => {
  return new Promise(resolve => fetch(url).then(resolve))
}).reduce((prev, current) => prev.then(current), Promise.resolve())

I didn’t have to write code like Promise.then().then().then()....

Conclusion

In this article, I introduced some methods for:

  • more shortly
  • more readable
  • more shallow nests
  • not to use temporary variables

Perhaps, you may not feel them so attractive.

But if you join more large project, it’s very important to write with such consciousness from day to day because small differences accumulate leads huge differences.

If there’re some methods that you haven’t known yet, I recommend you to start to use them.

Extra: Array.prototype.flatten()

There is a proposal Array useful method flatten. This method is already implemented in lodash to “flatten” a multidimensional array.

const array = [1, [2, 3], 4, [5, 6]]

array.flatten()
// [1, 2, 3, 4, 5, 6]

Someday, we’ll be able to use this method such that.