Javascript rename function (not variable name) - javascript

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.

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.

How to convert a string into function in 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/

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

calling a jQuery function named in a variable

I have several jQuery function like
function setOne();
setTwo(); setThree();
and a variable var number that values respectively "one", "two", "three".
How can I call function "setOne()" when number values "one", function "setTwo" when number values "two" and so on...?
Thank you so much in advance. Any help will be apreciated.
If you have your function in the global scope (on the window object) you can do:
// calls function setOne, setTwo, ... depending on number.
window["set" + number]();
And using eval will allow you to run functions in local scope:
eval("set" + number + "()");
When is JavaScript's eval() not evil?
Create a name -> function map:
var funcs = {
'one': setOne,
'two': setTwo
/*...*/
};
Then you call the function with:
funcs[number]();
If the variable details the actual name of the JQuery function and you want to apply the function to a DOM element like 'body', you can do the following:
$('body')['function-name']('params');
Provided your functions are in the global scope, try:
function setOne() {
console.log('setOne called');
}
function setTwo() {
console.log('setTwo called');
}
function setThree() {
console.log('setThree called');
}
var number, funcName;
number = 'one';
funcName = 'set' + number.charAt(0).toUpperCase() + number.slice(1);
window[funcName](); // output: setOne called
number = 'two';
funcName = 'set' + number.charAt(0).toUpperCase() + number.slice(1);
window[funcName](); // output: setTwo called
number = 'three';
funcName = 'set' + number.charAt(0).toUpperCase() + number.slice(1);
window[funcName](); // output: setThree called
As simple as this is:
function hello(){
alert("hello");
}
var str = "hello";
eval(str+"()");
Why do you have three functions for that?
var number;
function setNumber(n) {
number = n;
}
setNumber(1) will set number to 1
setNumber(2) will set number to 2
ect
Further to #Andreas answer, the following illustrates the approach when not using a global.
Make a variable that holds a set of functions:
var callbacks = {
setOne: function(params) {
// ...
},
setTwo: function(params) {
// ...
},
};
Then if you have a variable holding the function name, you can do:
var number = "Two";
callbacks["set" + number](params);

javascript is it possible to use a string to call a object function

I have a generic function which can speak to multiple other functions in appropriate objects is it possible to use a string to call the appropriate function.
var string = "save";
var generic = (new function (string) {
string."alert()";
return this;
})
var save = (new function (string) {
this.alert = (function () {
alert("your document has been saved")
return this
})
return this
})
var notSaved = (new function (string) {
this.alert = (function () {
alert("your document has not been saved")
return this
})
return this
})
I am using it for a far more complex set up but here is an example. Is this possible?
Sure you can. Try something like this:
window[string].alert();
Looking at your code it's hard to tell what you're actually trying to achieve. Nonetheless, here are a few ideas that may be relevant.
First, let's make a couple of objects:
var rabbit = {
name: 'Peter',
hop: function () {
return this.name + ' hopped!'
},
jump: function () {
return this.name + ' jumped!'
}
}
var hairy_maclary = {
name: 'Hairy Maclary',
jump: function () {
return this.name + ' jumped over the fence!'
}
}
Now, you could define a function which invokes the hop method on whichever object is passed to it:
function hop(object) {
return object.hop()
}
hop(rabbit) // 'Peter hopped!'
I'm not sure why you'd do this rather than invoking hop directly, but perhaps you want to do extra stuff before or afterwards.
If you wanted to you could create a completely generic function which would invoke a given method on a given object:
function invokeMethod(object, method) {
object[method]()
}
invokeMethod(hairy_maclary, 'jump') // 'Hairy Maclary jumped over the fence!'
This is a really strange thing to want to do, though. Perhaps you could provide more of an idea of what you're actually trying to do, since your example code is rather odd.
You can enclose your functions within some object so you can access by passing name of the property using some variable (in this case named string), eg. like that:
var string = 'notSaved';
var funcs = {};
funcs.save = new function(){
this.alert = function(){
alert('called save.alert()');
};
return this;
};
funcs.notSaved = new function(){
this.alert = function(){
alert('called notSaved.alert()');
};
return this;
};
funcs[string].alert();
See working example on jsfiddle.
If your variables are global (they should not), they are also automatically enclosed within window object, so you can call them also like that: window[string].alert(). This will not work for non-global functions (in this case my solution seems to be the only one not using eval()).
eval("alert('test');");
You can call functions with eval. Even you can declare functions.
eval("function test(){ alert("test");}");
test();

Categories

Resources