Reputation: 35
I have this object bellow :
let calc = {
data: null,
num: function(x){
this.data = x
return this
},
add: function(){
this.data += 4
return this
},
sub: function(){
this.data -= 2
return this
},
show: function(){
console.log(this.data)
}
}
so to calculate any number i simply do method chaining like bellow
calc.num(5).add().sub().show()
//output: 7
Problem: i was thinking if there is a way to replace the object property name from an array then execute it , look at this code bellow
// it supose to replace the items on the array then execute the object calls
let arr = [calc.add(), calc.sub(), calc.show()]
calc.num(5).arr[0].arr[1].arr[2]// <-- this will be translated
calc.num(5).add().sub().show() // <-- to this
i know that it tries to find arr[n] in the object and it will throw an error (undefined)
.. i want to achieve this specific case in any way guys OR similar solutions OR infos
Thank you in advance :)
Upvotes: 0
Views: 71
Reputation: 50684
Instead of using array indexes to try and build up your chain of method calls, you could make an array of function references (ie: uncalled functions, that can then later be called):
let arr = [calc.add, calc.sub, calc.show]; // no `()` after each method
using this, you can then use .reduce()
with .call()
to bind the this
based on the previous function call, for example;
const calc = { data: null, num: function(x) { this.data = x; return this }, add: function() { this.data += 4; return this }, sub: function() { this.data -= 2; return this }, show: function() { console.log(this.data) } };
const arr = [calc.add, calc.sub, calc.show];
arr.reduce((prev, fn) => fn.call(prev), calc.num(5));
// number to start with --------------------/\
Or, instead, you might extract .show()
and then call that manually yourself, that way you can call any other methods that might not be included in your array of methods:
const calc = { data: null, num: function(x) { this.data = x; return this }, add: function() { this.data += 4; return this }, sub: function() { this.data -= 2; return this }, show: function() { console.log(this.data) } };
const arr = [calc.add, calc.sub];
const res = arr.reduce((prev, fn) => fn.call(prev), calc.num(5));
res.show(); // call any other methods not in `arr`
This could be adapted to use a wrapper function if your functions take arguments, for example:
// add: function(x) {} <--- takes x as an argument and adds it to num/data.
const calc = { data: null, num: function(x) { this.data = x; return this }, add: function(x) { this.data += x; return this }, sub: function() { this.data -= 2; return this }, show: function() { console.log(this.data) } };
const arr = [function() {
return calc.add.call(this, 4); // <--- supply argument after `this` (eg: 4)
}, calc.sub, calc.show];
arr.reduce((prev, fn) => fn.call(prev), calc.num(5));
or, a similar adaption might be to create an object as each element, and specify the arguments (if any) in an array (this imo is a little cleaner as you don't need to use the function
keyword everywhere):
// add: function(x) {} <--- takes x as an argument and adds it to num/data.
const calc = { data: null, num: function(x) { this.data = x; return this }, add: function(x) { this.data += x; return this }, sub: function() { this.data -= 2; return this }, show: function() { console.log(this.data) } };
const arr = [{fn: calc.add, args: [4]}, {fn: calc.sub, args: []}];
const res = arr.reduce((prev, {fn, args}) => fn.apply(prev, args), calc.num(5));
res.show();
Upvotes: 3