How to convert a string into function in javascript? - javascript

I converted a function into string using stringify and stored into database.
But how to add this string as function to a variable
lets assume i get string like i am showing in A
var A = "function aF() {\n console.log(\'change1\');\n}"
I want to add aF function to a object key like this
{handle: A }
But i am getting this in result
{ handle: 'function aF() {\n console.log(\'change1\');\n }' }
instead i want this
{handle:[function: aF]} or {handle:[function]}
Because variable A is typeof string. Is there any way to convert A into function and then store into handle key.

You can use Function constructor to make a functions.
For Example.
var A = "function aF() {\n console.log(\'change1\');\n}" ;
var functionStr = A.substring(A.indexOf("{")+1, A.lastIndexOf("}"));
new Function(functionStr)();
Note:
Using a string to create function object with this method is as risky as eval(). You should not do it unless you are sure that user-input is not involved. If user-input is used in making a function string then function is not considered secure as user can potentially manipulate around the authentication and authorization since system cannot control (validate) the same.
what if function aF have some parameter
You need to store the reference to the function object and invoke the same with parameter, for example
var A = "function aF() {\n console.log(\'change1\');\n}" ;
var functionStr = A.substring(A.indexOf("{")+1, A.lastIndexOf("}"));
var functionObj = new Function(functionStr);
Now invoke this function with parameter, for example
functionObj ( args );
or use call
functionObj.call( this, args );//this is the context you want to bind to this funciton.
or use apply
functionObj.apply( this, args );//this is the context you want to bind to this funciton.

Heres how I would do it, this is pretty much another take on other responses but doesnt involve any sub-strings. The comments on the code pretty much say it all.
var yourExample = createFunction("function aF() {\n console.log(\'change1\');\n}");
yourExample(); // prints change1 in console
var fnWithParam = createFunction("function aF(param1) { console.log(param1); }");
fnWithParam(2); // prints 2 in console
// creates a function from a string, that string must be a function itself.
function createFunction(fnStr) {
// make a function which returns a function, unwrap that function by calling it with apply();
return new Function('return ' + fnStr).apply();
}
Also to help reduce your exposure to access to objects such as window or document you can create new variables inside the function scope which creates that function. For instance:
// creates a function from a string, that string must be a function itself.
function createFunction(fnStr) {
// make a function which returns a function, unwrap that function by calling it with apply();
return new Function('"use strict"; var window,document; return ' + fnStr).apply();
}
Now this doesnt solve all the security issues around creating javascript from strings but I think its better than nothing.
Good readings:
"use strict"; - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
new Function() - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

An other solution would be to do :
var A = "function aF() {\n console.log(\'change1\');\n}" ;
eval(A);
{handle:aF}

Good day.
I wrote small function.
It is very simple, without many validations.
See here
function makeFooFromString(str){
var m = str.match(/function\s+([^(]+?)\s*\(([^)]*)\)\s*{(.*)}/);
// function name
var fooname = m[1];
// function params
var params = m[2];
// function body
var body = m[3];
// processing params
if(params.length){
params = params.split(',');
for(var i = 0; i < params.length; i++){
params[i] = params[i].replace(/\s*/, '');
}
}else{
params = [];
}
params = params.join(',');
// make our temp function body
var text = '';
text += 'var foo = function('+params+'){'+body+'};';
text += 'return foo.apply(foo, arguments);';
return new Function(text);
};
Now i make call like this
var foo = makeFooFromString('function get_sum(a, b){ return a+b;}')
And test
console.log(foo);
console.log(foo(1, 2));
console.log(foo(3, 4));
See it on jsfiddle
https://jsfiddle.net/j586xajq/

Related

Correct way to execute a function when I have function name

I have a string "Car.run(true)" or "Car.find('window')", I want to execute the function run or find and also pass respective parameters passed. What is the correct way to do it without using eval?
I tried to split the string, extracted the function name and parameters using regex but issue is with boolean values(it will a string after extraction).
Can anyone guide me to resolve this blocker?
In javascript land, classes are just objects that can be referenced using dictionary lookup syntax
class Car { run(x) { return x } find(x) { return x } }
car = new Car()
method_name = 'run'
car[method_name] # == ƒ run(x) { return x }
car[method_name](1) # == 1
In python land you would need hasattr() and getattr()
You can try simply like below, if you dont want to use eval:
var functionHolder = "Car.run(true)";
var myTmpFunction = new Function(functionHolder);
myTmpFunction (); //This would invoke
Generally using eval is not a good idea, and this isn't great either but it's a start:
function Car() {
this.run = function(args) {
console.log('Running', args)
}
}
const str = "Car.run(true)";
// Get the constructor name and the function with arguments as a string
const [ctor, fn] = str.split('.');
// The name of the function without parens
const fnName = fn.replace(/\((.+)\)/, '')
// Get the argument list of the function
const originalArgs = fn.match(/\((.+)\)/)
// Clean arguments
const args = originalArgs[1]
.split(',')
.map(str => str.trim())
.filter(Boolean);
// Instantiate a new object based on the name
const f = new(Function.prototype.bind.apply(window[ctor]))();
// Invoke the function with the arguments
f[fnName].apply(f, args) // Running true
General idea comes from the AngularJS source and how it instantiates objects from strings.

Javascript rename function (not variable name)

I am trying to change the name of the function that is given by .toString(), or create a new function with a new name but the same body.
function func() {}
func.toString() // returns 'function func() {}'
changename(func, "newname") // this is the functionality that I am trying to achieve
func.toString() // should now return 'function newname() {}'
I have tried using Object.defineProperty() which sucessfully updates the value returned by func.name but not func.toString().
Object.defineProperty(func, "name", {
value: "newname",
writable: true,
});
func.name // returns 'newname'
func.toString() // still returns 'function func() {}'
Edit: Reason for wanting to do this
I need take take an arbitrary function with an unknown name and write it to a file with a known name, for example (using nodejs):
const fs = require("fs");
changename(func, "newname");
fs.writeFileSync("tmp.js", func.toString());
tmp.js then contains:
function newname() {}
If all you need to do is write the code of the function to a file, just regex replace the name with whatever you want:
let func = // whatever;
let funcCode = func.toString();
funcCode = funcCode.replace(/^function [^(]*(.*)$/, "function newName$1");
Now funcCode has the text you can dump out to a file.
Changing the reported "name" property of an actual function object is another story entirely, and is either impossible or impractical at best. If you're just working with the text of the function, it's easy.
If you are okay with extending toString function, this should work:
function func() {}
func.toString() // returns 'function func() {}'
changeName=function(funcToExtend, name){
funcToExtend.toString = () => name;
}
changeName(func,"new name");
func.toString(); // new name
One way to do this is to change how the toString function works. I don't think this is a good solution but I came up with this:
function test(){
console.log('hello');
}
test.newName = 'helloFunc';
test.toString = function(){
var str = Function.prototype.toString.call(this);
return 'function ' + this.newName + str.substring(str.indexOf('('), str.length);
}
console.log(test.toString());
I believe that a much nicer solution could implement the Function constructor.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
If you want just a new String with the new name, you can do this way:
function func() {}
console.log(func.toString())
Object.prototype.changeName = function (newName) {
return "function " + newName + "(){}";
}
let newNameFunction = func.changeName("newName")
console.log(newNameFunction);
But this way, you don't have the body of the function.

Create a JavaScript function dynamically from a string name

Given a string classname, I want to dynamically create a new JavaScript function named after that string that can be used to instantiate objects.
I've tried using eval() but for some reason the declared function does not appear in the global (window) scope.
eval( "function " + classname + "() {}" );
window[ classname ]; // => undefined
Is there a way I can dynamically create a new function named after a string?
Or, alternatively, give me some way to reference the created function after creating it via eval. Interestingly it appears as a local variable when I debug it in Safari.
Update:
Got it! Of course it's obvious, I just use eval again to create the instance:
var myInstance = eval( "new " + classname );
myInstance.constructor.name; // => classname (yay)
This should work in my case because I only need to create one instance of the class right after it's declared. For the general case though see Pointy's answer.
Yes:
window[classname] = function() { ... };
Now, in honesty, that's not exactly like what you were attempting, but it's pretty close. When you instantiate a function via a function expression like that, and without a name, the function can't refer to itself except via the name in the outer scope (in this case, the global scope).
If that's important, what you could do is this: create the function with some stock "internal" name, and then assign it to the global name:
function secretName() { ... }
window[classname] = secretName;
function registerFunction(functionBody) {
"use strict";
var script = document.createElement("script");
script.innerHTML = "function " + functionBody;
document.body.appendChild(script);
}
registerFunction("fooBar(x, y) { return x + y; }");
fooBar(1, 2); // will give you 3
Although this is essentially the same as eval() but it will register the function in the domain of the current page. You can later remove this script element, or reuse it for other functions.
Try this:
var classname = "myFunction";
window[ classname ] = function () {};
alert( window[ classname ] ); // => undefined
In case you don't want to create new functions based on some string, but based on another similar function: (this might not be a good example but hope you can get the idea)
function createListOfFunctions(functionNameList) {
resultFunctions = {};
// Loop all names to create a list of functions with those names
$.each(functionNameList, function(index, functionName) {
resultFunctions[functionName] = _createFunction(functionName);
});
return resultFunctions;
}
function _createFunction(name) {
return function(anotherNameToCompare) {
// customize this funciton whatever you like
return name == anotherNameToCompare;
};
}
// USAGE:
functionNameList = ['stack', 'overflow'];
result = createListOfFunctions(functionNameList); // result = { stack: function(name) {...}, overflow: function(name) {...} }
result.stack('stack'); // true
result.stack('not stack'); // false
result.overflow('overflow'); // true

Dynamically firing a named-spaced method via JavaScript

I have multiple external JavaScripts that are namespaced based on the section of the site. I am trying to dynamically fire methods, but am unable to get the methods to fire. Can anyone tell me what the problem is?
If I add this, the method fires:
Namespace.Something.init()
But when I try to do it like this, nothing happens (note: namespace equals Namespace.Something and functionname equals init):
namespace[functionname]();
Unless you want to use eval which I am sure you don't the following works.
This assumes that all your methods are the same level deep i.e namespace.somename.somemethod
var Namespace = {
Something: {
init: function() {
console.log('init called');
}
}
};
Namespace.Something.init();
var namespace = "Namespace";
var section = "Something";
var method = "init";
this[namespace][section][method]();
as Namespace is part of the global scope you can access it from this[namespace]
I asked the same question a few weeks ago, though I think I phrased it slightly differently. See this.
Basically, you need to parse the string functionname one piece at a time.
By the way, using the walk_path code from that answer, here's a general purpose function I wrote to run a function from a string including arguments.
// run an arbitrary function from a string. Will attempt to parse the args from parenthesis, if none found, will
// use additional arguments passed to this function.
utils.runFunction = function (funcdef) {
var argPos = funcdef.indexOf('(');
var endArgPos = -1;
var args = undefined;
var func = funcdef;
if (argPos > 0) {
endArgPos = funcdef.indexOf(')', argPos);
if (endArgPos > 0) {
args = funcdef.substring(argPos + 1, endArgPos).split(',');
func = funcdef.substring(0, argPos - 1);
}
} else {
args = Array.prototype.slice.call(arguments, 1);
}
var func = walk_path(window, func);
return !args ? func() : func.apply(null, args);
};
var methodName = 'Namespace.Something.init';
var methodParts = methodName.split('.');
var method = this;
for (var i=0; i < methodParts.length; i++) {
method = method[methodParts[i]];
};
method(the arguments you want);

Getting object name within the objectscope

I have a Javascript class that contains
add
remove
removeall
update
.
.
.
updateLik
.
.
functions.
And in my Serverside script a have Links like
Add
Now if user click on the DIV, the function "add" will be called.
and the add function calls in turn the updateLink function.
updateLink replaces the onclick attribute to "myobject.delete(100)"
Now my problem is that in updateLink function i had to hardcode the objectname
to call its delete function.
Is there any way to get the objectname, or any other solution?
Thanks
You could store a reference of the context where your object is created, and then search within it, looking for the actual instance:
function MyClass() {
this.getVarName = function () {
for (var name in this.scope)
if (this.scope[name] === this)
return name;
}
}
MyClass.prototype.scope = this;
var myObject = new MyClass();
myObject.getVarName(); // returns "myObject"
Simplest way is to use eval.
var myObject = eval(myObjectName);
That is if you have the name of the object in a string format.
I would also look at at the YUI event library. It allows you to execute any function in any scope.
http://developer.yahoo.com/yui/event/
Example:
var x = new YourClass();
var y = x;
Question: What is the name of your object? x or y?
Solution:
var x = new YourClass('x'); // and have your class copy the name
or
var x = new YourClass();
x.name = 'x';
delete is a keyword so you cannot use it with dot-notation (object.method). You have to use ['property']-notation (object['method']).
var obj = {delete: function(){}}; // throws a syntax error
var obj = {'delete': function(){}}; // works
obj.delete() // throws a syntax error
obj['delete']() // works

Categories

Resources