Right here we go. Ones that don’t make sense (*eg* `reduce`

itself, `toString`

, etc, etc) are commented out. I just realised I forgot `flatMap`

, but I should be doing work anyway, so hey ho. I haven’t tested *all* of them so there may be a few slight errors.

One thing to note is how I’ve exited the loop where necessary: `reduce`

*et al* are designed to iterate through an entire array. But the fourth argument to the `reduce`

callback is the actual array currently being iterated over. By mutating it using `splice`

when I want to break out of it, I can change the length (`thisArr.splice(1)`

). Because the length has been changed and there are no more entries, reduce will finish iterating. **Note that this will actually mutate the input array, so this is an awful hack that won’t generally be useful in practice, it’s just used as an example here because I didn’t have time to think of anything better.**

- no mutator methods (push, pop, shift, unshift or splice). These are used within the
`reduce`

function
- no reflection-like methods (
`toSource`

*etc*) as they don’t make sense in this context.
- no
`sort`

as I’m not writing a sort implementation
- no
`reduce`

or `reduceRight`

as that defeats the point (however… *)

Just to clarify, don’t actually do any of this , it’s all pretty awful (though on the whole I think it’s fairly efficient), use the defined methods

```
function at(arr, n) {
if (n < 0) {
n = arr.length + n;
}
return arr.reduce((acc, v, i, thisArr) => {
if (i === n) {
thisArr.splice(1);
return v;
} else {
return acc;
}
}, undefined);
}
// function concat() {}
function copyWithin(arr, target, start = 0, end = arr.length) {
let replaceCount = end - start;
return arr.reduce((acc, v, i) => {
if (i >= target && replaceCount !== 0) {
acc[i] = arr[end - replaceCount];
replaceCount--
} else {
acc[i] = v;
}
return acc;
}, []);
}
function entries(arr) {
return arr.reduce((acc, v, i) => {
acc.push([i, v]);
return acc;
}, []);
}
function every(arr, cb) {
return arr.reduce((acc, v, _i, thisArr) => {
if (!cb(v)) {
thisArr.splice(1);
return false;
}
return acc;
}, true);
}
function fill(arr, val, start = 0, end = arr.length) {
// NOTE slightly incomplete: I haven't handled negative values:
return arr.reduce((acc, v, i) => {
if (i >= start && i < end) {
acc[i] = val;
} else {
acc[i] = v;
}
return acc;
}, []);
}
function filter(arr, cb) {
return arr.reduce((acc, v) => {
if (cb(v)) {
acc.push(v);
}
return acc;
}, [])
}
function find(arr, cb) {
return arr.reduce((acc, v, _i, thisArr) => {
if (cb(v)) {
thisArr.splice(1);
return v;
}
return acc;
}, undefined);
}
function findIndex(arr, cb) {
return arr.reduce((acc, v, i, thisArr) => {
if (cb(v)) {
thisArr.splice(1);
return i;
}
return acc;
}, -1);
}
function flat(arr, depth = 1) {
if (depth > 0) {
return arr.reduce((acc, val) => {
if (Array.isArray(val)) {
acc.push(flat(val, depth - 1));
} else {
acc.push(val);
}
return acc;
}, [])
} else {
return slice(arr);
}
}
function flatMap(arr, cb) {}
function forEach(arr, cb) {
return arr.reduce((acc, val) => {
cb(val);
return acc;
}, undefined);
}
function includes(arr, val) {
return arr.reduce((acc, v, _i, thisArr) => {
if (v === val) {
thisArr.splice(1);
return true;
} else {
return acc;
}
}, false)
}
function indexOf(arr, val) {
return arr.reduce((acc, v, i, thisArr) => {
if (v === val) {
thisArr.splice(1);
return i;
} else {
return acc;
}
}, -1)
}
function join(arr, joiner = ",") {
return arr.reduce((acc, v, i) => {
if (i === 0) {
return `${v}`;
} else {
return `${acc}${joiner}${v}`;
}
}, "")
}
function keys(arr) {
return arr.reduce((acc, _v, i) => {
acc.push(i);
return acc;
}, [])
}
function lastIndexOf(arr, val) {
return arr.reduce((acc, v, i) => {
if (v === val) {
return i;
} else {
return acc;
}
}, -1)
}
function map(arr, cb) {
return arr.reduce((acc, v) => {
acc.push(cb(v));
return acc;
}, [])
}
// function pop() {}
// function push() {}
// function reduce() {}
// function reduceRight() {}
function reverse(arr) {
return arr.reduce((acc, v) => {
acc.unshift(v);
return acc;
}, []);
}
// function shift() {}
function slice(arr, start = 0, end = arr.length) {
if (start < 0) {
start = end + start;
}
return arr.reduce((acc, v, i, thisArr) => {
if (i >= end) {
thisArr.splice(1);
} else if (i >= start) {
acc.push(v);
}
return acc;
}, [])
}
function some(arr, cb) {
return arr.reduce((acc, v, _i, thisArr) => {
if (cb(v)) {
thisArr.splice(1);
return true;
} else {
return acc;
}
}, false)
}
// function sort() {}
// function splice() {}
// function toLocaleString() {}
// function toSource() {}
// function toString() {}
// function unshift() {}
function values(arr) {
return arr.reduce((acc, v) => {
acc.push(v);
return acc
}, []);
}
```

* bonus. I think this is robust – anyway all the above can use this instead of the `Array.prototype.reduce`

, although doing that would be an even more terrible idea:

```
function reduce(arr, cb, acc, i = 0) {
const [head, ...tail] = arr;
if (head === undefined) {
return acc;
} else {
return reduce(tail, cb, cb(acc, head, i, arr), i + 1);
}
}
```