# 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?

&nbsp;

## 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!

&nbsp;

## Array methods

1.  [indexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) [⬇](#indexof)
2.  [lastIndexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf)  [⬇](#lastindexof)
3.  [includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) [⬇](#includes)
4.  [push](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) [⬇](#push)
5.  [pop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) [⬇](#pop)
6.  [unshift](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) [⬇](#unshift)
7.  [shift](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) [⬇](#shift)
8.  [concat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) [⬇](#concat)
9.  [reverse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) [⬇](#reverse)
10.  [slice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) [⬇](#slice)
11.  [splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) [⬇](#splice)
12. [flat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) [⬇](#flat) (You can use `isArray` method)

&nbsp;

## The Solutions

&nbsp;

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

  return -1
}
``` 

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

  return -1
}
```

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

  return false
}
``` 

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

  return array.length
}
```

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

  return lastItem
}
```

### unshift
```js
// 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
```js
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
```js
function concat(array, ...rest) {
  let result = [...array]

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

  return result
}
```

### reverse
```js
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
```js
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
```js
// 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
```js
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
```js
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 
}
```

&nbsp;

## 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. 

&nbsp;
