Let's write native JavaScript Array methods from scratch! (Challenge)

Let's write native JavaScript Array methods from scratch! (Challenge)

Introduction

Native JavaScript methods exist to nourish and enrich our developer experience. But what if they simply vanished? After all, it's 2020. Anything can happen right? 😜. Well, that's the case here in this article. But we are software developers and are confident that we can overcome any problems that we encounter 💪!

So here is the challenge!

Can you write the JavaScript Array methods listed below from scratch?

 

The Rules

  • Don't use prototype. Instead, take the array as the first argument/parameter.
  • Don't use other native JavaScript methods to solve the problems
  • Feel free to use the latest ECMAScript standards such as the rest operator, spread operator, default values, etc...
  • Pay attention to understand if a method modifies the original array or returns a new array! Or if anything is returned at all.
  • Don't look up the solutions until you really tried!

Notice I haven't included any *Higher-order functions (filter, map, etc...). That's for the next challenge!

 

Array methods

  1. indexOf
  2. lastIndexOf
  3. includes
  4. push
  5. pop
  6. unshift
  7. shift
  8. concat
  9. reverse
  10. slice
  11. splice
  12. flat (You can use isArray method)

 

The Solutions

 

indexOf

function indexOf(array, value) {
  for(let i=0; i<array.length; i++) {
    if(array[i] === value) {
      return i
    }
  }

  return -1
}

lastIndexOf

function lastIndexOf(array, value) {
  for(let i=array.length-1; i >=0; i--) {
    if(array[i] === value) {
      return i
    }
  }

  return -1
}

includes

function includes(array, value) {
  for(const item of array) {
    if(item === value) {
      return true
    }
  }

  return false
}

push

function push(array, value) {
  array[array.length] = value

  return array.length
}

pop

function pop(array) {
  const lastItem = array[array.length-1]

  array.length = array.length - 1

  return lastItem
}

unshift

// Here is my attempt, can you do better?
function unshift(array, value) {
  const length = array.length
  let previous
  let temp

  for(let i=0; i<length; i++) {
      if(i === 0) {
        previous = array[i+1]
        array[i+1] = array[i]
      } else {
        temp = array[i+1]
        array[i+1] = previous
        previous = temp
      }
  }
  array[0] = value

  return array.length
}

shift

function shift(array) {
  const firstItem = array[0]

  for(let i=0; i<array.length; i++) {
    array[i] = array[i+1]
  }
  array.length = array.length - 1  

  return firstItem
}

concat

function concat(array, ...rest) {
  let result = [...array]

  for(const arr of rest) {
    result = [...result, ...arr]
  }

  return result
}

reverse

function reverse(array) {
  let start = 0
  let end = array.length-1

  while(start < end) {
    const temp = array[start]
    array[start] = array[end]
    array[end] = temp
    start++
    end--
  }

  return array
}

slice

function slice(array, start, end=array.length) {
  if(!start && start !== 0) {
    return [...array]
  }
  if(start < 0) {
    start = array.length + start
  }
  if(end < 0) {
    end = array.length + end
  }
  const result = []

  for(let i=start; i<end; i++) {
    result.push(array[i])
  }

  return result
}

splice

// I couldn't figure out how to modify the original array
// I also return the newly spliced array instead of an array of removed items
// can you implement the correct behavior?
function splice(array, start, deleteCount, ...addition) {
  const firstArray = []
  const lastArray = []

  for(let i=0; i<start; i++) {
    firstArray[i] = array[i]
  }

  for(let i=start+deleteCount, j=0; i<array.length; i++, j++) {
    lastArray[j] = array[i]
  }

  return [...firstArray, ...addition, ...lastArray]
}

join

function join(array, value = ',') {
  let result = ''

  for(let i=0; i<array.length; i++) {
    if(i === array.length - 1) {
      result += array[i]
      break
    }

    result += array[i] + value
  }

  return result
}

flat

function flat(array, depth = 1, currentDepth = 0) {
  let result = []

  for(const item of array) {
    if(Array.isArray(item) && depth !== currentDepth) {
      result = [...result, ...flat(item, depth, currentDepth + 1)]
    } else {
      result.push(item)
    }
  }

  return result 
}

 

Parting words 👋

I hope you enjoyed the challenge as much as I did! 🎉. Feel free to provide any feedback including 🐛's. I would also love to see your codes, feel free to post them as comments. Thank you and adios.