but how can handle this chain:
list.create([10, 2, 2, 3, 1, 2, 4]).unique().asc();
In order to chain methods like that, each method (at least before the last method in the chain) must return an object that has the next method on it. Your unique
method returns an array, not the list
object, so it doesn't have an asc
method. In order to have that chain, you'd need unique
to return something with asc
.
In this specific example, you might use an augmented array. You could directly augment an array instance, but for chains like you're describing, you probably want multiple instances of list
(not just one), so that suggests an Array
subclass:
class List extends Array {
static fromList(list) { // Requires either no argument or an iterable argument
const fromList = new this();
if (list) {
fromList.push(...list);
}
return fromList;
}
asc() {
const fromList = this.constructor.fromList(this);
fromList.sort((a, b) => a - b);
return fromList;
}
desc() {
const fromList = this.constructor.fromList(this);
fromList.sort((a, b) => b - a);
return fromList;
}
unique() {
return this.constructor.fromList(new Set(this));
}
}
const new_list = List.fromList([10, 2, 2, 3, 1, 2, 4]).unique().asc();
console.log(new_list);
That example always creates a new instance of List
for each operation, but you can also do it where it mutates and returns the original list:
class List extends Array {
static fromList(list) { // Requires either no argument or an iterable argument
const fromList = new this();
if (list) {
fromList.push(...list);
}
return fromList;
}
asc() {
return this.sort((a, b) => a - b);
}
desc() {
return this.sort((a, b) => b - a);
}
unique() {
const set = new Set(this);
this.length = 0;
this.push(...set);
return this;
}
}
const new_list = List.fromList([10, 2, 2, 3, 1, 2, 4]).unique().asc();
console.log(new_list);
Alternatively, you might use a builder pattern where you store up the things to do and then have a "go" terminal operation that does all the steps.
Note: Creating augmented array classes like List
is fine, but beware that the subclass needs to handle all the signatures of the original Array
constructor, which is...eccentric. If you pass new Array
a single argument that's a number, it creates a sparse array with that length and no elements in it. If you pass it a single argument that isn't a number, it creates an array with that value as its only element. If you pass it multiple arguments, it creates an array with those elements in it. That's why I used a static fromList
method rather than writing our own List
constructor.