Mr Salsa
Mr Salsa

Reputation: 35

js: replacing object property name call from an array

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

Answers (1)

Nick Parsons
Nick Parsons

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

Related Questions