0

I'm trying to apply this function How parameterize array to as single comma separated value? in a 'function called by its name' script but it doesn't work as expected:

function add(a,b,c){
    return a+b+c
}

var vals = callFct("add", window, 2,3,4); 
document.getElementById('result').innerHTML += "<br>Function result: "+vals
// result = Function result: 9 ----> 2+3+4 : OK

The values are coming from: json={a:[2,3,4]}

function serialize(vals){
    var output = [];
    for (var prop in vals) {
        if (vals.hasOwnProperty(prop)){
            output.push(vals[prop].join(','));
        }
    }
    return output;
}

var json = {a:[2,3,4]};
document.getElementById('result').innerHTML += "<br>Used data:  "+serialize(json)
// result = Used data: 2,3,4 ---> seems to be OK... but

var test = callFct("add", window, serialize(json)); 
document.getElementById('result').innerHTML += "<br>Function result:  "+test
// result = Function result : 2,3,4undefinedundefined ---> oups

I've tried to remove the 'undefined' ...

document.getElementById('result').innerHTML += "<br>Function result :  "+test.replace(/undefined/g,'')
// result = Function result : 2,3,4 ---> nope

The called function:

function callFct(w, y, z ) {  
  var z = Array.prototype.slice.call(arguments, 2);
  console.log('vars = '+z)
  let v = w.split(".");
  let x = v.pop();
  for(var i = 0; i < v.length; i++) {
    y = y[v[i]];
  }
  return y[x].apply(y, z);
}

What's wrong in my way to proceed?

4
  • 1
    Why don't you use JSON.stringify? Commented Jun 30, 2020 at 12:56
  • The json variable is an object, not JSON (which is a text format), and serialize does not turn it into JSON. It turns it into an array of strings. Commented Jun 30, 2020 at 13:02
  • You'll need to show the code for callFct if you want help with that. Commented Jun 30, 2020 at 13:03
  • function added in question Commented Jun 30, 2020 at 13:07

2 Answers 2

1

Please provide better parameter names than w, y, and z...

If you change the names to the one's seen in the demo below, your return statement will look like the following:

return scope[last].apply(funcName, serialized);

If you notice, you are calling apply on window.add. Make sure that method exists. I am not sure what add looks like, but it will take the "serialized" JSON data and the scope of the call will be the incoming string (first) parameter (which can apparently be dot-separated).

Notes

  1. You can change this: [...output, json[prop].join(',')] to this: output.concat(json[prop].join(',')) for browser compatability.
  2. A "basic" polyfill for flatMap can be found here: https://stackoverflow.com/a/39838385/1762224

const json = { a: [2, 3, 4] };

document.getElementById('result-1').innerHTML = 'Values: ' + serialize(json);

let sum = callFct('add', window, serialize(json));
document.getElementById('result-2').innerHTML = 'Sum: ' + sum;

let difference = callFct('subtract', window, serialize(json));
document.getElementById('result-3').innerHTML = 'Difference: ' + difference;

function serialize(json) {
  return Object.keys(json).reduce((output, prop) => {
    return [...output, json[prop].join(',')];
  }, []);
}

function callFct(funcName, scope, serialized) {
  serialized = Array.from(arguments).slice(2);
  console.log('vars = ' + serialized)
  const tokens = funcName.split('.');
  const last = tokens.pop();
  for (let i = 0; i < tokens.length; i++) {
    scope = scope[tokens[i]];
  }
  return scope[last].apply(funcName, serialized);
}

function prepareValues(serialized) {
  return serialized
    .flatMap(v => v.split(/,\s*/g))
    .map(v => parseInt(v, 10));
}

function add(serialized) {
  return prepareValues(serialized)
    .reduce((s, v) => s + v, 0);
}

function subtract(serialized) {
  return prepareValues(serialized)
    .reduce((s, v) => s - v);
}
div[id^="result-"] { font-family: monospace; }
<script src="https://polyfill.io/v3/polyfill.min.js?features=Array.prototype.flatMap"></script>
<div id="result-1"></div>
<div id="result-2"></div>
<div id="result-3"></div>

Sign up to request clarification or add additional context in comments.

5 Comments

it doesn't solve the prob: used data produced as explained in the question are right (2,3,4) but not in an exploitable format by function.
@Wolden OK, with your included function, that you provided after I originally answered, I tried to explain what is happening.
@Wolden I updated my add function to flat-map the results and then split the values. Your serialize is returning an array of "serialized" values. It is not a true string. You are building the results as an array of the joined values for each key.
yeeeeeeees thanks so much, it works perfectly :-) ...btw, is there a "classical way" to replace flatMap which is not yet recognized by all browsers?
@Wolden you can create a polyfill. I will add it to the question.
0

Finally found a simpliest solution:

// define empty vars
let a, b, c;    
const vars = [a, b, c];

// call function by its name
function callFct(fct) {  
  const toks = fct.split(".");
  const last = toks.pop();
  for(var i = 0; i < toks.length; i++) {
    window = window[toks[i]];
  }
  return window[last].apply(window, vars); // vars now in array
}

// functions to be called
function add(){
   return a+b+c
}
function substract(){
   return a-b-c
}  
function multiply(){
   return a*b*c
}

// produce real vars values
a = 20, b = 10, c = 5;

// get results
var add = callFct("add");
console.log(add); // 20+10+5 = 35

c = -5 // actualize any value
var subs = callFct("substract");
console.log(subs); // 20-10--5 = 15

var mult = callFct("multiply");
console.log(mult); // -1000

// mixing functions results
function mix(){
    return add/subs
}
var mixed = callFct("mix");
console.log(mixed); // 2.3333333333333335

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.