First, thought we already have overcome the evil eval, right? Plus, I am working in pure JavaScript.
So I have an object:
var MyObj = new Object();
MyObj.myFunction = function(a, b) { return a + b; }
But this function is stored in a string, and the Function constructor ask for the parameters first, and than the body after, and I don't know about the parameters, if exists. The point is to create the function by "interpreting" (not EVALuating) the content of the string. I wish this was possible:
var MyObj = new Object();
var myFuncStr = "function(a, b) { return a + b; }";
MyObj.myFunction = new Function(myFuncStr);
I found this discussion from 11 years ago: Given a string describing a Javascript function, convert it to a Javascript function But this was a decade ago and the answer is for a specific case.
I am thinking in try to identify the parameters inside the string and try to pass to the Function constructor, something like a String.toFunction extension that will require some code (maybe I locate the first parentheses, get the slice, locate the brackets, get the content... voilá, seems a bit rust).
Is there an answer already for this situation? Any existing solutions?
EDIT: Since there is a lot of votes asking for a step back, I will post the code one level up (two will be about 3k lines)
Object.defineProperty(String.prototype, "toObject", {
enumerable: false,
configurable: false,
writable: false,
value: function(method, extended) {
var string = this;
if(!method) method = "typeof";
let ini = string.indexOf('{');
let fim = string.lastIndexOf('}');
if(ini==-1 || fim==-1) {
$monitor("Erro de parâmetro String.toObject","erro","O parâmetro passado a String.toObject ("+string+") não é um objeto literal.");
return null;
}
var str = string.slice(ini+1, fim);
console.log("String.toObject str...");
console.log(str);
var Elems = str.split(','), Terms, prop, value, isStr, val, type, dp = new DOMParser();
var Obj = new Object();
for(let i=0; i<Elems.length; i++) {
Terms = Elems[i].split(':');
prop = Terms.shift().filter('property');
value = Terms.join(':').filter('value');
console.log(" ...filter "+prop+" : "+value);
isStr = (value.charAt(0)=='"' && value.charAt(value.length-1)=='"');
switch(method) {
case "typeof":
val = (isStr)? value.slice(1,-1) : value ;
type = (isStr)? "string" : val.typeof(extended) ;
break;
case "string":
val = (isStr)? value.slice(1,-1) : value ;
type = "string";
break;
default:
$monitor("Erro de parâmetro String.toObject","erro","O parâmetro 'method' ("+method+") passado a String.toObject não é válido.");
return null;
}
switch(type) {
case "null":
Obj[prop] = null;
break;
case "boolean":
Obj[prop] = (val.toLowerCase()=="true");
break;
case "number":
Obj[prop] = Number.parseFloat(val);
break;
case "string":
Obj[prop] = val;
break;
case "function":
Obj[prop] = "StackOverflowWillGiveMeTheAnswer";
break;
case "xml":
Obj[prop] = dp.parseFromString(val, "text/xml");
break;
case "object":
Obj[prop] = val.toObject(extended);
break;
}
}
return Obj;
}
});
But this function depends on typeof, so here is:
Object.defineProperty(String.prototype, "typeof", {
enumerable: false,
configurable: false,
writable: false,
value: function(extended) {
var string = this;
if(string.length==0 && extended) return "null";
if(string.toLowerCase()=="true" || string.toLowerCase()=="false") return "boolean";
if(string.isNumeric()) return "number";
if(string.replaceAll(' ','').substring(0, 9)=='function(' || string.replaceAll(' ','').substring(0, 5)=='()=>{') return 'function';
string = string.trim();
if(extended) {
try {
var DOM = new DOMParser();
var xml = DOM.parseFromString(string, "text/html");
return "xml";
} catch(e) {}
} else {
if(string.charAt(0)=='<' && string.charAt(string.length-1)=='>') return "xml";
}
//console.log("String.typeof chr 0 -1: "+string.charAt(0)+" "+string.charAt(string.length-1));
if(string.charAt(0)=='{' && string.charAt(string.length-1)=='}') return "object";
return "string";
}
});
Both are in development, not 100% functional yet. I was avoiding to post so much code because of the downvotes, will take my chances. Just give me an answer instead of just asking why... sometimes God only knows why!
By the way, "no you can't" is an answer.