Files
jsrt/lib/stdlib/array.js
T
2026-10-03 14:06:24 +00:00

154 lines
4.2 KiB
JavaScript

// 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);