// Arrays. The compiler gives only `a[i]`, `a[i] = x` and `a.length`, which can // also be written. Every method here is built on those // // Not as the spec says: // - A method takes one value where the spec takes any number (`push(x)`, // `unshift(x)`, `concat(other)`), because more need rest params // - A callback gets the element and its index, not the array too // - Holes are not skipped: a callback sees undefined for a hole // `Array(n)` and `new Array(n)` make an array of `n` holes function Array(n) { const a = []; if (n !== undefined) a.length = n; return a; } Array.prototype = { // ── Change the array ── push(x) { this[this.length] = x; return this.length; }, pop() { if (this.length === 0) return undefined; const x = this[this.length - 1]; this.length = this.length - 1; return x; }, shift() { if (this.length === 0) return undefined; const x = this[0]; for (let i = 1; i < this.length; i++) this[i - 1] = this[i]; this.length = this.length - 1; return x; }, unshift(x) { for (let i = this.length; i > 0; i--) this[i] = this[i - 1]; this[0] = x; return this.length; }, reverse() { for (let i = 0, j = this.length - 1; i < j; i++, j--) { const x = this[i]; this[i] = this[j]; this[j] = x; } return this; }, fill(x, start, end) { const len = this.length; const s = relativeIndex(start === undefined ? 0 : start, len); const e = relativeIndex(end === undefined ? len : end, len); for (let i = s; i < e; i++) this[i] = x; return this; }, // ── Read ── at(i) { if (i < 0) i += this.length; return this[i]; }, indexOf(x, from) { for (let i = from === undefined ? 0 : relativeIndex(from, this.length); i < this.length; i++) { if (this[i] === x) return i; } return -1; }, lastIndexOf(x) { for (let i = this.length - 1; i >= 0; i--) { if (this[i] === x) return i; } return -1; }, includes(x) { return this.indexOf(x) !== -1; }, join(sep) { const s = sep === undefined ? "," : sep; let out = ""; for (let i = 0; i < this.length; i++) { if (i > 0) out = out + s; const x = this[i]; if (x !== undefined && x !== null) out = out + String(x); } return out; }, toString() { return this.join(","); }, // ── Make a new array ── slice(start, end) { const len = this.length; const s = relativeIndex(start === undefined ? 0 : start, len); const e = relativeIndex(end === undefined ? len : end, len); const out = []; for (let i = s; i < e; i++) out[i - s] = this[i]; return out; }, concat(other) { const out = this.slice(); for (let i = 0; i < other.length; i++) out[out.length] = other[i]; return out; }, // ── With a callback ── forEach(f) { for (let i = 0; i < this.length; i++) f(this[i], i); }, map(f) { const out = []; for (let i = 0; i < this.length; i++) out[i] = f(this[i], i); return out; }, filter(f) { const out = []; for (let i = 0; i < this.length; i++) { if (f(this[i], i)) out[out.length] = this[i]; } return out; }, reduce(f, init) { let acc = init; for (let i = 0; i < this.length; i++) acc = f(acc, this[i], i); return acc; }, find(f) { for (let i = 0; i < this.length; i++) { if (f(this[i], i)) return this[i]; } return undefined; }, findIndex(f) { for (let i = 0; i < this.length; i++) { if (f(this[i], i)) return i; } return -1; }, some(f) { for (let i = 0; i < this.length; i++) { if (f(this[i], i)) return true; } return false; }, every(f) { for (let i = 0; i < this.length; i++) { if (!f(this[i], i)) return false; } return true; }, }; __link_proto_array(Array.prototype);