Reputation: 333
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?
Upvotes: 0
Views: 535
Reputation: 333
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
Upvotes: 0
Reputation: 48600
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).
[...output, json[prop].join(',')]
to this: output.concat(json[prop].join(','))
for browser compatability.flatMap
can be found here: https://stackoverflow.com/a/39838385/1762224const 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>
Upvotes: 1