loading...

Reimplementing JavaScript Array methods

webit profile image webit ・4 min read

This is cross-post from medium, where I published it first.

Array.filter() implementation

Some time ago I’ve found list of JavaScript tasks. Those cover all developer career levels — Newbie/Junior/Mid and are fun way to practice programming.
NOTE those tasks are written in Polish language but I’m gonna translate task requirements to English :)

I’ve decided to give it a try and reimplement some of commonly used JavaScript Array methods.

The task

Task #6 —Array methods
since JS is functional language it’s worth mastering its basic methods

.map
.filter
.reduce
.reduceRight
.every
.some
.entries

Create functions that will work same way as original Array methods. Functions has to use for or while loops

We also got function signatures:

function mapFn(array, callback){}
function filterFn(array, callback){}
function reduceFn(array, callback, initial){}
function reduceRightFn(array, callback, initial){}
function everyFn(array, callback){}
function someFn(array, callback){}
function entriesFn(array){}

Easy, right?
Let’s check…

Array.map()

The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
MDN

That was easy to build. All we need is to execute callback function on each array element and return value into new array. When finished iterating over elements — return new array. Pretty easy…

function mapFn(array, callback) {
  const out = [];
  for (let i of array) {
    out.push(callback(i));
  }
  return out;
}

Array.filter()

The filter() method creates a new array with all elements that pass the test implemented by the provided function.
MDN

Again, nothing fancy here. We need to create new array and push there elements only if callback’s test is passed:

function filterFn(array, callback) {
  const out = [];
  for (let i of array) {
    callback(i) && out.push(i);
  }
  return out;
}

Array.reduce()

The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
MDN

Reduce, required a bit more work. Callback accepts up to 4 parameters, and function itself can have (optional) initial value. If initial value is omitted we need to take 1st array element instead of.

Callback functions accepts 4 parameters:

  1. accumulator (accumulates callback’s return value)
  2. currentValue (current array element value)
  3. index (current array index)
  4. array (complete entry array)

Additionally in case reducer has no initial value we need to take 1st array item as it!

function reduceFn(array, callback, initial) {
  let out = initial;
  for (let i in array) {
    // in case initial value is missing we take 1st element of an array
    if (out === undefined) {
      out = array[i];
      continue;
    }
    out = callback(out, array[i], i, array);
  }
  return out;
}

Array.reduceRight()

The reduceRight() method applies a function against an accumulator and each value of the array (from right-to-left) to reduce it to a single value.
MDN

It is similar function to previous one but it starts executing callback function from the right (from the end). Iterates from highest array index to lowest one.

Similar to Array.reduce() initial value can be omitted — in such a case we need to take last array element as it.

Again, initial value might be omitted so we need to take array item as it. In case reduceRight() it's a last item of array!

function reduceRightFn(array, callback, initial) {
  let index = array.length;
  let out = initial;
  while (--index > -1) {
    // in case initial value is missing we take last element of an array
    if (out === undefined) {
      out = array[index];
      continue;
    }
    out = callback(out, array[index], index, array);
  }
  return out;
}

Array.every()

The every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value.
MDN

According to the description we need to build function that checks if every element in array passes callback test. That means if at least one check won’t pass — we need return false. That’s all!

function everyFn(array, callback) {
  for (let i of array) {
    if (!callback(i)) {
      return false;
    }
  }
  return true;
}

That simple solution also covers special case:

Caution: Calling this method on an empty array will return true for any condition!

Array.some()

The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.
MDN

As you can see Array.some() is similar to Array.every() the difference is subtle — we got true response as soon as at least one element passes callback test.

function someFn(array, callback) {
  for (let i of array) {
    if (callback(i)) {
      return true;
    }
  }
  return false;
}

Again, special case is covered:

Caution: Calling this method on an empty array returns false for any condition!

Array.entries()

The entries() method returns a new Array Iterator object that contains the key/value pairs for each index in the array.
MDN

That was most challenging for me. Most probably because I rarely create custom iterators or work with generators…

Even though I guess I’ve nailed it? ;)

function entriesFn(array) {
  const out = {};
  out[Symbol.iterator] = function* () {
    for (let i in array) {
      yield [+i, array[i]];
    }
  };
  return out;
}

What do you think?

Do you like such a practice tasks?

Posted on May 7 by:

webit profile

webit

@webit

Web developer 💻// Cycling addicted 🚴🏼‍♂️// Making web since last century 🦖

Discussion

markdown guide