Dynamic function name in javascript? - javascript

I have this:
this.f = function instance(){};
I would like to have this:
this.f = function ["instance:" + a](){};

This will basically do it at the most simple level:
"use strict";
var name = "foo";
var func = new Function(
"return function " + name + "(){ alert('sweet!')}"
)();
//call it, to test it
func();
If you want to get more fancy, I have a written an article on "Dynamic function names in JavaScript".

You can use Object.defineProperty as noted in the MDN JavaScript Reference:
var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});

In recent engines, you can do
function nameFunction(name, body) {
return {[name](...args) {return body.apply(this, args)}}[name]
}
const x = nameFunction("wonderful function", (p) => p*2)
console.log(x(9)) // => 18
console.log(x.name) // => "wonderful function"
Thanks to T S for pointing out the need to preserve this in the comments.
Also, these days, I'd probably use the Object.defineProperty approach to achieve something similar.

Update 2021: CherryDT's answer should be the easiest most straight forward way now, but it doesn't work consistently with different browsers for stack traces or Function.prototype.toString(), so if you need that you're stuck with this less convenient solution.
Old answer: Many suggestions here are suboptimal, by using eval, hacky solutions or wrappers.
As of ES2015 names are inferred from the syntactic position for variables and properties.
So this will work just fine:
const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'
Resist the temptation to create named function factory methods as you wouldn't be able to pass the function from outside and retrofit it into the syntactic position to infer its name. Then it's already too late. If you really need that, you have to create a wrapper. Someone did that here, but that solution doesn't work for classes (which are also functions).
A much more in-depth answer with all the variants outlined has been written here: https://stackoverflow.com/a/9479081/633921

As others mentioned, this is not the fastest nor most recommended solution. Marcosc's solution below is the way to go.
You can use eval:
var code = "this.f = function " + instance + "() {...}";
eval(code);

What about
this.f = window["instance:" + a] = function(){};
The only drawback is that the function in its toSource method wouldn't indicate a name. That's usually only a problem for debuggers.

The syntax function[i](){} implies an object with property values that are functions, function[], indexed by the name, [i].
Thus
{"f:1":function(){}, "f:2":function(){}, "f:A":function(){}, ... } ["f:"+i].
{"f:1":function f1(){}, "f:2":function f2(){}, "f:A":function fA(){}} ["f:"+i] will preserve function name identification. See notes below regarding :.
So,
javascript: alert(
new function(a){
this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a]
}("A") . toSource()
);
displays ({f:(function () {})}) in FireFox.
(This is almost the same idea as this solution, only it uses a generic object and no longer directly populates the window object with the functions.)
This method explicitly populates the environment with instance:x.
javascript: alert(
new function(a){
this.f=eval("instance:"+a+"="+function(){})
}("A") . toSource()
);
alert(eval("instance:A"));
displays
({f:(function () {})})
and
function () {
}
Though the property function f references an anonymous function and not instance:x, this method avoids several problems with this solution.
javascript: alert(
new function(a){
eval("this.f=function instance"+a+"(){}")
}("A") . toSource()
);
alert(instanceA); /* is undefined outside the object context */
displays only
({f:(function instanceA() {})})
The embedded : makes the javascript function instance:a(){} invalid.
Instead of a reference, the function's actual text definition is parsed and interpreted by eval.
The following is not necessarily problematic,
The instanceA function is not directly available for use as instanceA()
and so is much more consistent with the original problem context.
Given these considerations,
this.f = {"instance:1": function instance1(){},
"instance:2": function instance2(){},
"instance:A": function instanceA(){},
"instance:Z": function instanceZ(){}
} [ "instance:" + a ]
maintains the global computing environment with the semantics and syntax of the OP example as much as possible.

The most voted answer has got already defined [String] function body. I was looking for the solution to rename already declared function's name and finally after an hour of struggling I've dealt with it. It:
takes the alredy declared function
parses it to [String] with .toString() method
then overwrites the name (of named function) or appends the new one (when anonymous) between function and (
then creates the new renamed function with new Function() constructor
function nameAppender(name,fun){
const reg = /^(function)(?:\s*|\s+([A-Za-z0-9_$]+)\s*)(\()/;
return (new Function(`return ${fun.toString().replace(reg,`$1 ${name}$3`)}`))();
}
//WORK FOR ALREADY NAMED FUNCTIONS:
function hello(name){
console.log('hello ' + name);
}
//rename the 'hello' function
var greeting = nameAppender('Greeting', hello);
console.log(greeting); //function Greeting(name){...}
//WORK FOR ANONYMOUS FUNCTIONS:
//give the name for the anonymous function
var count = nameAppender('Count',function(x,y){
this.x = x;
this.y = y;
this.area = x*y;
});
console.log(count); //function Count(x,y){...}

For setting the name of an existing anonymous function:
(Based on #Marcosc's answer)
var anonymous = function() { return true; }
var name = 'someName';
var strFn = anonymous.toString().replace('function ', 'return function ' + name);
var fn = new Function(strFn)();
console.log(fn()); // —> true
Demo.
Note: Don't do it ;/

The function's name property by default isn't writeable, but since it's configurable we can still use Object.defineProperty to change it. Since Object.defineProperty conveniently returns the object itself, we can write a function with a dynamic name like this:
const theName = 'foobar'
const fn = Object.defineProperty(function () {
/* ... */
}, 'name', { value: theName })
console.log(fn.name) // Logs foobar
Of course this could be factored out into a helper function:
const nameFunction = (name, fn) => Object.defineProperty(fn, 'name', { value: name })
const fn = nameFunction('foobar', function () {
/* ... */
})
console.log(fn.name) // Logs foobar
The above nameFunction function can also be used to rename an existing function, of course (here it's just renaming and returning the anonymous one).

Dynamic methods of an object may be created using Object Literal Extensions provided by ECMAScript 2015 (ES6):
const postfixes = ['foo', 'bar'];
const mainObj = {};
const makeDynamic = (postfix) => {
const newMethodName = 'instance: ' + postfix;
const tempObj = {
[newMethodName]() {
console.log(`called method ${newMethodName}`);
}
}
Object.assign(mainObj, tempObj);
return mainObj[newMethodName]();
}
const processPostfixes = (postfixes) => {
for (const postfix of postfixes) {
makeDynamic(postfix);
}
};
processPostfixes(postfixes);
console.log(mainObj);
The output of running the code above is:
"called method instance: foo"
"called method instance: bar"
Object {
"instance: bar": [Function anonymous],
"instance: foo": [Function anonymous]
}

the best way it is create object with list of dynamic functions like:
const USER = 'user';
const userModule = {
[USER + 'Action'] : function () { ... },
[USER + 'OnClickHandler'] : function () { ... },
[USER + 'OnCreateHook'] : function () { ... },
}

There are two methods to achieve this, and they have their pros and cons.
name property definition
Defining immutable name property of a function.
Pros
Every character is available for the name. (eg. () 全 {}/1/얏호/ :D #GO(#*#%! /*)
Cons
The function's syntactic (“expressional”) name may not correspond with its name property value.
Function expression evaluation
Making a named function expression and evaluating it with Function constructor.
Pros
The function's syntactic (“expressional”) name always corresponds with its name property value.
Cons
Whitespaces (and etc.) are not available for the name.
Expression-injectable (eg. For input (){}/1//, the expression is return function (){}/1//() {}, gives NaN instead of a function.).
const demoeval = expr => (new Function(`return ${expr}`))();
// `name` property definition
const method1 = func_name => {
const anon_func = function() {};
Object.defineProperty(anon_func, "name", {value: func_name, writable: false});
return anon_func;
};
const test11 = method1("DEF_PROP"); // No whitespace
console.log("DEF_PROP?", test11.name); // "DEF_PROP"
console.log("DEF_PROP?", demoeval(test11.toString()).name); // ""
const test12 = method1("DEF PROP"); // Whitespace
console.log("DEF PROP?", test12.name); // "DEF PROP"
console.log("DEF PROP?", demoeval(test12.toString()).name); // ""
// Function expression evaluation
const method2 = func_name => demoeval(`function ${func_name}() {}`);
const test21 = method2("EVAL_EXPR"); // No whitespace
console.log("EVAL_EXPR?", test21.name); // "EVAL_EXPR"
console.log("EVAL_EXPR?", demoeval(test21.toString()).name); // "EVAL_EXPR"
const test22 = method2("EVAL EXPR"); // Uncaught SyntaxError: Unexpected identifier

If you want to have a dynamic function like the __call function in PHP, you could use Proxies.
const target = {};
const handler = {
get: function (target, name) {
return (myArg) => {
return new Promise(resolve => setTimeout(() => resolve('some' + myArg), 600))
}
}
};
const proxy = new Proxy(target, handler);
(async function() {
const result = await proxy.foo('string')
console.log('result', result) // 'result somestring' after 600 ms
})()

You can use Dynamic Function Name and parameters like this.
1) Define function Separate and call it
let functionName = "testFunction";
let param = {"param1":1 , "param2":2};
var func = new Function(
"return " + functionName
)();
func(param);
function testFunction(params){
alert(params.param1);
}
2) Define function code dynamic
let functionName = "testFunction(params)";
let param = {"param1":"1" , "param2":"2"};
let functionBody = "{ alert(params.param1)}";
var func = new Function(
"return function " + functionName + functionBody
)();
func(param);

This utility function merge multiple functions into one (using a custom name), only requirement is that provided functions are properly "new lined" at start and end of its scoop.
const createFn = function(name, functions, strict=false) {
var cr = `\n`, a = [ 'return function ' + name + '(p) {' ];
for(var i=0, j=functions.length; i<j; i++) {
var str = functions[i].toString();
var s = str.indexOf(cr) + 1;
a.push(str.substr(s, str.lastIndexOf(cr) - s));
}
if(strict == true) {
a.unshift('\"use strict\";' + cr)
}
return new Function(a.join(cr) + cr + '}')();
}
// test
var a = function(p) {
console.log("this is from a");
}
var b = function(p) {
console.log("this is from b");
}
var c = function(p) {
console.log("p == " + p);
}
var abc = createFn('aGreatName', [a,b,c])
console.log(abc) // output: function aGreatName()
abc(123)
// output
this is from a
this is from b
p == 123

I had better luck in combining Darren's answer and kyernetikos's answer.
const nameFunction = function (fn, name) {
return Object.defineProperty(fn, 'name', {value: name, configurable: true});
};
/* __________________________________________________________________________ */
let myFunc = function oldName () {};
console.log(myFunc.name); // oldName
myFunc = nameFunction(myFunc, 'newName');
console.log(myFunc.name); // newName
Note: configurable is set to true to match the standard ES2015 spec for Function.name1
This especially helped in getting around an error in Webpack similar to this one.
Update: I was thinking of publishing this as an npm package, but this package from sindresorhus does exactly the same thing.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

I struggled a lot with this issue. #Albin solution worked like a charm while developing, but it did not work when I changed it to production. After some debugging I realized how to achieve what I needed. I'm using ES6 with CRA (create-react-app), which means it's bundled by Webpack.
Lets say you have a file that exports the functions you need:
myFunctions.js
export function setItem(params) {
// ...
}
export function setUser(params) {
// ...
}
export function setPost(params) {
// ...
}
export function setReply(params) {
// ...
}
And you need to dynamically call these functions elsewhere:
myApiCalls.js
import * as myFunctions from 'path_to/myFunctions';
/* note that myFunctions is imported as an array,
* which means its elements can be easily accessed
* using an index. You can console.log(myFunctions).
*/
function accessMyFunctions(res) {
// lets say it receives an API response
if (res.status === 200 && res.data) {
const { data } = res;
// I want to read all properties in data object and
// call a function based on properties names.
for (const key in data) {
if (data.hasOwnProperty(key)) {
// you can skip some properties that are usually embedded in
// a normal response
if (key !== 'success' && key !== 'msg') {
// I'm using a function to capitalize the key, which is
// used to dynamically create the function's name I need.
// Note that it does not create the function, it's just a
// way to access the desired index on myFunctions array.
const name = `set${capitalizeFirstLetter(key)}`;
// surround it with try/catch, otherwise all unexpected properties in
// data object will break your code.
try {
// finally, use it.
myFunctions[name](data[key]);
} catch (error) {
console.log(name, 'does not exist');
console.log(error);
}
}
}
}
}
}

Node.js JavaScript Class Based Dynamic Function Name
File: Schema.js
class Schema {
constructor() {
this.name = null;
}
virtual(name = null) {
this.name = name;
return this;
}
get(func = false) {
if (!this.name || !func instanceof Function) {
throw new Error("Name and function must be provided.");
}
// Attach the dynamic function name to the "this" Object
this[this.name] = func;
this.name = null;
}
}
module.exports = Schema;
File: index.js
const Schema = require("./Schema.js");
const User = new Schema();
User.virtual("getPostCount").get(() => {
return 10 + 10;
});
const ok = User.getPostCount();
console.log({ User });
console.log(ok);

Thank you Marcosc! Building on his answer, if you want to rename any function, use this:
// returns the function named with the passed name
function namedFunction(name, fn) {
return new Function('fn',
"return function " + name + "(){ return fn.apply(this,arguments)}"
)(fn)
}

function myFunction() {
console.log('It works!');
}
var name = 'myFunction';
window[name].call();

You was near:
this["instance_" + a] = function () {...};
{...};

I might be missing the obvious here, but what's wrong with just adding the name? functions are invoked regardless of their name. names are just used for scoping reasons. if you assign it to a variable, and it's in scope, it can be called. hat happens is your are executing a variable which happens to be a function. if you must have a name for identification reasons when debugging, insert it between the keyword function and the opening brace.
var namedFunction = function namedFunction (a,b) {return a+b};
alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());
an alternative approach is to wrap the function in an outer renamed shim, which you can also pass into an outer wrapper, if you don't want to dirty the surrounding namespace. if you are wanting to actually dynamically create the function from strings (which most of these examples do), it's trivial to rename the source to do what you want. if however you want to rename existing functions without affecting their functionality when called elsewhere, a shim is the only way to achieve it.
(function(renamedFunction) {
alert(renamedFunction(1,2));
alert(renamedFunction.name);
alert(renamedFunction.toString());
alert(renamedFunction.apply(this,[1,2]));
})(function renamedFunction(){return namedFunction.apply(this,arguments);});
function namedFunction(a,b){return a+b};

This is BEST solution, better then new Function('return function name(){}')().
Eval is fastest solution:
var name = 'FuncName'
var func = eval("(function " + name + "(){})")

Related

How do I know who has instantiated a function? [duplicate]

I am creating a JavaScript code and I had a situation where I want to read the object name (string) in the object method. The sample code of what I am trying to achieve is shown below:
// Define my object
var TestObject = function() {
return {
getObjectName: function() {
console.log( /* Get the Object instance name */ );
}
};
}
// create instance
var a1 = TestObject();
var a2 = TestObject();
a1.getObjectName(); // Here I want to get the string name "a1";
a2.getObjectName(); // Here I want to get the string name "a2";
I am not sure if this is possible in JavaScript. But in case it is, I would love to hear from you guys how to achieve this.
This is not possible in JavaScript. A variable is just a reference to an object, and the same object can be referenced by multiple variables. There is no way to tell which variable was used to gain access to your object. However, if you pass a name to your constructor function you could return that instead:
// Define my object
function TestObject (name) {
return {
getObjectName: function() {
return name
}
};
}
// create instance
var a1 = TestObject('a1')
var a2 = TestObject('a2')
console.log(a1.getObjectName()) //=> 'a1'
console.log(a2.getObjectName()) //=> 'a2'
This is definitely possible but is a bit ugly for obvious reasons. I think this can have some application in debugging. The solution makes use of the ability to get the line number for a code using Error object and then reading the source file to get the identifier.
let fs = require('fs');
class Foo {
constructor(bar, lineAndFile) {
this.bar = bar;
this.lineAndFile = lineAndFile;
}
toString() {
return `${this.bar} ${this.lineAndFile}`
}
}
let foo = new Foo(5, getLineAndFile());
console.log(foo.toString()); // 5 /Users/XXX/XXX/temp.js:11:22
readIdentifierFromFile(foo.lineAndFile); // let foo
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
function getLineAndFile() {
let err = getErrorObject();
let callerLine = err.stack.split("\n")[4];
let index = callerLine.indexOf("(");
return callerLine.slice(index+1, callerLine.length-1);
}
function readIdentifierFromFile(lineAndFile) {
let file = lineAndFile.split(':')[0];
let line = lineAndFile.split(':')[1];
fs.readFile(file, 'utf-8', (err, data) => {
if (err) throw err;
console.log(data.split('\n')[parseInt(line)-1].split('=')[0].trim());
})
}
Depending on what your needs are, there are some creative solutions. The main place I want to know a variable name is when I'm debugging.
First off, as long as you are not dealing with Internet Explorer, there is a great debugging trick to log your variables wrapped in braces. The console will show you the details of your "object"... which has only one key, the exact name of your variable!
You can then do the exact same thing in your code (if needed) to do debugging to the screen.
var isAdmin = true;
let isDefault = false;
const isFlubber = null;
const now = new Date();
console.log({isAdmin});
console.log({isDefault});
console.log({isFlubber});
console.log({now});
//You can also use console.dir() or console.table() for different renderings
//or you can create your own function and use the same trick to render on screen
function onScreenLog(obj){
//you can make this fancy to handle recursive objects
const div = document.getElementById('onscreen-log');
for(const [key, value] of Object.entries(obj)){
div.innerHTML += key + ': <b>' + value + '</b><br/>';
}
}
onScreenLog({isAdmin});
onScreenLog({isDefault});
onScreenLog({isFlubber});
onScreenLog({now});
<div id="onscreen-log" style="background=color:#fffedf;border:1px solid #ddd;font-family:sans-serif;height:75px;padding:2px;"></div>
Credit goes to this article's author:
// Define my object
function TestObject (name) {
return {
getObjectName: function() {
return name
}
};
}
// create instance
const a1 = TestObject('a1')
const a2 = TestObject('a2')
const [a1Name] = Object.keys({a1})
const [a2Name] = Object.keys({a2})
console.log(a1Name) //=> 'a1'
console.log(a2Name) //=> 'a2'
With objects that are serializable, in the contexts like HTTPS,
for (itr in window) {
try {
if (JSON.stringify(window[itr])==JSON.stringify(this)){
alert(itr) //return itr
}
} catch (err) {}
};/**************************************************************************/(new Audio('https://ia804500.us.archive.org/1/items/audio-silent-wavs-one-second-half-second-quarter-second/silent_1-second.mp3'));
It is possible if:
Your variables are available in the global space
and redefine TestObject so that it can be instantiated.
// Define my object
function TestObject(){}
TestObject.prototype.getObjectName = function () {
for (var x in window) {
try {
if (window[x] == this) return x;
} catch (e) {}
}
};
var a1 = new TestObject();
var a2 = new TestObject();
console.log(a1.getObjectName());
console.log(a2.getObjectName());

Store object in the localStorage

// Extending the Storage object:
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
}
Storage.prototype.getObject = function(key) {
var value = this.getItem(key);
return value && JSON.parse(value);
}
// START HERE:
var dog = {
name : '',
woof : function(){ console.log('woof woof, I am ' + this.name); }
}
dog.name = 'Lovely';
//Store in the localstorage
localStorage.setObject('mydog', dog);
//Get from the localstorage
var mydog = localStorage.getObject('mydog');
console.log(mydog.name); // prints 'Lovely'
console.log(mydog.woof()); // ootest.html:36 Uncaught TypeError: mydog.woof is not a function(…)
Why I am getting that error ?
The right way: use object constructor
let Dog = function(name) {
this.name = name
}
Dog.prototype.woof = function woof() {
console.log('woof woof, I am ' + this.name);
}
// Create a 'static' method for a Dog 'class'
Dog.fromJSON = function fromJSON(json) {
return new Dog(JSON.parse(json).name)
}
// Instantinate your objects with `new` keyword
let dog = new Dog('Lovely')
dog.woof()
let storedDog = JSON.stringify(dog)
console.log('stored:', storedDog)
// Dog.fromJSON() returns new Dog object,
// with the same parameters for a constructor
// and with all methods
let restoredDog = Dog.fromJSON(storedDog)
restoredDog.woof()
Limitation
This approach will work well only for objects than will behave similar if created with similar constructor parameter. If you want to store objects with rich data inside, please refer to How come JSON can't save object's functions? accepted answer.
Just for learning something new: storing functions in JSON
Functions can be created from string at runtime via Function object. To create function it we need to pass arguments and body:
new Function ([arg1[, arg2[, ...argN]],] functionBody)
To get a method params and body we need to call inherited toString() method on method:
dog.woof.toString()
We can store function declaration in string and we can create function from string. Next steps are: implement conventional functions storage as object properties, implement restoring saved functions from JSON string.
Dirty working implementation example in the snippet below.
Why you should not implement this?
Security risk. Somebody could hack the serialised functions with any arbitrary code.
Bad code design. Having objects without predefined constructors leads to maintenance hell, because you can't you javascript duck typing to make assumptions about object behavior.
Versioning. If you update you code, you can't be sure about which version of objects stored on clients.
let dog = {
name : '',
woof : function() {
console.log('woof woof, I am ' + this.name);
}
}
dog.name = 'Lovely';
dog.woof()
let storedDog = saveWithFuncToJSON(dog)
console.log('stored:', storedDog)
let restoredDog = restoreWithFuncFromJSON(storedDog)
restoredDog.woof()
console.log("Don't use this approach in production!")
// Code below is created only for fun,
// if you need this code in production,
// then your code smells
// Return JSON string
function saveWithFuncToJSON(object) {
// Use Object.assign() just for simplicity,
// something more solid needed for real object copying
let preparedObject = Object.assign({}, object)
for (let prop in preparedObject) {
if (typeof(preparedObject[prop]) !== 'function') continue
// Different platforms constructing function string in different ways
// so you'll have to put a lot of efforts to make it work stable
let funcStr = preparedObject[prop].toString()
let startParams = funcStr.indexOf('(') + 1
let endParams = funcStr.indexOf(')')
let hasParams = (endParams - startParams)
let funcParams = !hasParams ? [] : funcStr.slice(
funcStr.indexOf('(') + 1,
funcStr.indexOf('\n')
).split(',')
let funcBody = funcStr.slice(
funcStr.indexOf('{') + 1,
funcStr.lastIndexOf('}')
)
// This is the most interesting part
// We will store function as a string like freezing humans
preparedObject[`__${prop}Func`] = {
params: funcParams,
body: funcBody
}
}
return JSON.stringify(preparedObject)
}
function restoreWithFuncFromJSON(jsonSting) {
let object = JSON.parse(jsonSting)
for (let prop in object) {
// Functions to be restored should be named differently
let shouldConvertToFunc = prop.startsWith('__') && prop.endsWith('Func')
if (!shouldConvertToFunc) continue
let funcName = prop.slice(2, -4)
let funcData = object[prop]
let contructorArgsArray = funcData.params.concat([funcData.body])
// Function() does all work for us
object[funcName] = Function.apply(null, contructorArgsArray)
delete object[prop]
}
return object;
}
LocalStorage only supports strings. You can store objects with JSON-encoding, but that won't work for your functions.
JSON only supports numbers, strings, booleans, arrays, and basic object structures.

How to dynamically set a function/object name in Javascript as it is displayed in Chrome

This is something which has been bugging me with the Google Chrome debugger and I was wondering if there was a way to solve it.
I'm working on a large Javascript application, using a lot of object oriented JS (using the Joose framework), and when I debug my code, all my classes are given a non-sensical initial display value. To see what I mean, try this in the Chrome console:
var F = function () {};
var myObj = new F();
console.log(myObj);
The output should be a single line which you can expand to see all the properties of myObj, but the first thing you see is just ▶ F.
My issue is that because of my OO framework, every single object instantiated gets the same 'name'. The code which it looks is responsible for this is like so:
getMutableCopy : function (object) {
var f = function () {};
f.prototype = object;
return new f();
}
Which means that in the debugger, the initial view is always ▶ f.
Now, I really don't want to be changing anything about how Joose instantiates objects (getMutableCopy...?), but if there was something I could add to this so that I could provide my own name, that would be great.
Some things that I've looked at, but couldn't get anywhere with:
> function foo {}
> foo.name
"foo"
> foo.name = "bar"
"bar"
> foo.name
"foo" // <-- looks like it is read only
Object.defineProperty(fn, "name", { value: "New Name" });
Will do the trick and is the most performant solution. No eval either.
I've been playing around with this for the last 3 hours and finally got it at least somewhat elegant using new Function as suggested on other threads:
/**
* JavaScript Rename Function
* #author Nate Ferrero
* #license Public Domain
* #date Apr 5th, 2014
*/
var renameFunction = function (name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
/**
* Test Code
*/
var cls = renameFunction('Book', function (title) {
this.title = title;
});
new cls('One Flew to Kill a Mockingbird');
If you run the above code, you should see the following output to your console:
Book {title: "One Flew to Kill a Mockingbird"}
Combine usage of computed property name to dynamically name a property, and inferred function naming to give our anonymous function that computed property name:
const name = "aDynamicName"
const tmp = {
[name]: function(){
return 42
}
}
const myFunction= tmp[name]
console.log(myFunction) //=> [Function: aDynamicName]
console.log(myFunction.name) //=> 'aDynamicName'
One could use whatever they want for 'name' here, to create a function with whatever name they want.
If this isn't clear, let's break down the two pieces of this technique separately:
Computed Property Names
const name = "myProperty"
const o = {
[name]: 42
}
console.log(o) //=> { myProperty: 42 }
We can see that the property name assigned on o was myProperty, by way of computed property naming. The []'s here cause JS to lookup the value inside the bracket, and to use that for the property name.
Inferred Function Naming
const o = {
myFunction: function(){ return 42 }
}
console.log(o.myFunction) //=> [Function: myFunction]
console.log(o.myFunction.name) //=> 'myFunction'
Here we use inferred function naming. The language looks at the name of wherever the function is being assigned to, & gives the function that inferred name.
We can combine these two techniques, as shown in the beginning. We create an anonymous function, which gets it's name via inferred function naming, from a computed property name, which is the dynamic name we wanted to create. Then we have to extract the newly created function from the object it is embedded inside of.
Example Using Stack Trace
Naming a supplied anonymous function
// Check the error stack trace to see the given name
function runAnonFnWithName(newName, fn) {
const hack = { [newName]: fn };
hack[newName]();
}
runAnonFnWithName("MyNewFunctionName", () => {
throw new Error("Fire!");
});
Although it is ugly, you could cheat via eval():
function copy(parent, name){
name = typeof name==='undefined'?'Foobar':name;
var f = eval('function '+name+'(){};'+name);
f.prototype = parent;
return new f();
}
var parent = {a:50};
var child = copy(parent, 'MyName');
console.log(child); // Shows 'MyName' in Chrome console.
Beware: You can only use names which would be valid as function names!
Addendum: To avoid evaling on every object instantiation, use a cache:
function Cache(fallback){
var cache = {};
this.get = function(id){
if (!cache.hasOwnProperty(id)){
cache[id] = fallback.apply(null, Array.prototype.slice.call(arguments, 1));
}
return cache[id];
}
}
var copy = (function(){
var cache = new Cache(createPrototypedFunction);
function createPrototypedFunction(parent, name){
var f = eval('function '+name+'(){};'+name);
f.prototype = parent;
return f;
}
return function(parent, name){
return new (cache.get(name, parent, typeof name==='undefined'?'Foobar':name));
};
})();
This won't totally solve your problem, but I would suggest overriding the toString method on the class's prototype. For instance:
my_class = function () {}
my_class.prototype.toString = function () { return 'Name of Class'; }
You'll still see the original class name if you enter an instance of my_class directly in the console (I don't think it's possible to do anything about this), but you'll get the nice name in error messages, which I find very helpful. For instance:
a = new my_class()
a.does_not_exist()
Will give the error message: "TypeError: Object Name of Class has no method 'does_not_exist'"
If you want to dynamically create a named function. You can use new Function to create your named function.
function getMutableCopy(fnName,proto) {
var f = new Function(`function ${fnName}(){}; return ${fnName}`)()
f.prototype = proto;
return new f();
}
getMutableCopy("bar",{})
// ▶ bar{}
Similar to #Piercey4 answer, but I had to set the name for the instance as well:
function generateConstructor(newName) {
function F() {
// This is important:
this.name = newName;
};
Object.defineProperty(F, 'name', {
value: newName,
writable: false
});
return F;
}
const MyFunc = generateConstructor('MyFunc');
const instance = new MyFunc();
console.log(MyFunc.name); // prints 'MyFunc'
console.log(instance.name); // prints 'MyFunc'
normally you use window[name] like
var name ="bar";
window["foo"+name] = "bam!";
foobar; // "bam!"
which would lead you to a function like:
function getmc (object, name) {
window[name] = function () {};
window[name].prototype = object;
return new window[name]();
}
but then
foo = function(){};
foobar = getmc(foo, "bar");
foobar; // ▶ window
foobar.name; // foo
x = new bar; x.name; // foo .. not even nija'ing the parameter works
and since you can't eval a return statement (eval("return new name()");), I think you're stuck
I think this is the best way to dynamically set the name of a function :
Function.prototype.setName = function (newName) {
Object.defineProperty(this,'name', {
get : function () {
return newName;
}
});
}
Now you just need to call the setName method
function foo () { }
foo.name; // returns 'foo'
foo.setName('bar');
foo.name; // returns 'bar'
foo.name = 'something else';
foo.name; // returns 'bar'
foo.setName({bar : 123});
foo.name; // returns {bar : 123}
Based on the answer of #josh, this prints in a console REPL, shows in console.log and shows in the debugger tooltip:
var fn = function() {
return 1917;
};
fn.oldToString = fn.toString;
fn.toString = function() {
return "That fine function I wrote recently: " + this.oldToString();
};
var that = fn;
console.log(that);
Inclusion of fn.oldToString() is a magic which makes it work. If I exclude it, nothing works any more.
With ECMAScript2015 (ES2015, ES6) language specification, it is possible to dynamically set a function name without the use of slow and unsafe eval function and without Object.defineProperty method which both corrupts function object and does not work in some crucial aspects anyway.
See, for example, this nameAndSelfBind function that is able to both name anonymous functions and renaming named functions, as well as binding their own bodies to themselves as this and storing references to processed functions to be used in an outer scope (JSFiddle):
(function()
{
// an optional constant to store references to all named and bound functions:
const arrayOfFormerlyAnonymousFunctions = [],
removeEventListenerAfterDelay = 3000; // an auxiliary variable for setTimeout
// this function both names argument function and makes it self-aware,
// binding it to itself; useful e.g. for event listeners which then will be able
// self-remove from within an anonymous functions they use as callbacks:
function nameAndSelfBind(functionToNameAndSelfBind,
name = 'namedAndBoundFunction', // optional
outerScopeReference) // optional
{
const functionAsObject = {
[name]()
{
return binder(...arguments);
}
},
namedAndBoundFunction = functionAsObject[name];
// if no arbitrary-naming functionality is required, then the constants above are
// not needed, and the following function should be just "var namedAndBoundFunction = ":
var binder = function()
{
return functionToNameAndSelfBind.bind(namedAndBoundFunction, ...arguments)();
}
// this optional functionality allows to assign the function to a outer scope variable
// if can not be done otherwise; useful for example for the ability to remove event
// listeners from the outer scope:
if (typeof outerScopeReference !== 'undefined')
{
if (outerScopeReference instanceof Array)
{
outerScopeReference.push(namedAndBoundFunction);
}
else
{
outerScopeReference = namedAndBoundFunction;
}
}
return namedAndBoundFunction;
}
// removeEventListener callback can not remove the listener if the callback is an anonymous
// function, but thanks to the nameAndSelfBind function it is now possible; this listener
// removes itself right after the first time being triggered:
document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
{
e.target.removeEventListener('visibilitychange', this, false);
console.log('\nEvent listener 1 triggered:', e, '\nthis: ', this,
'\n\nremoveEventListener 1 was called; if "this" value was correct, "'
+ e.type + '"" event will not listened to any more');
}, undefined, arrayOfFormerlyAnonymousFunctions), false);
// to prove that deanonymized functions -- even when they have the same 'namedAndBoundFunction'
// name -- belong to different scopes and hence removing one does not mean removing another,
// a different event listener is added:
document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
{
console.log('\nEvent listener 2 triggered:', e, '\nthis: ', this);
}, undefined, arrayOfFormerlyAnonymousFunctions), false);
// to check that arrayOfFormerlyAnonymousFunctions constant does keep a valid reference to
// formerly anonymous callback function of one of the event listeners, an attempt to remove
// it is made:
setTimeout(function(delay)
{
document.removeEventListener('visibilitychange',
arrayOfFormerlyAnonymousFunctions[arrayOfFormerlyAnonymousFunctions.length - 1],
false);
console.log('\nAfter ' + delay + 'ms, an event listener 2 was removed; if reference in '
+ 'arrayOfFormerlyAnonymousFunctions value was correct, the event will not '
+ 'be listened to any more', arrayOfFormerlyAnonymousFunctions);
}, removeEventListenerAfterDelay, removeEventListenerAfterDelay);
})();
I have not seen anyone mention the use of ES6 Proxies. Which in my opinion solve this problem beautifully. So here it is.
function shadow(object, secondObject) {
return new Proxy(object, {
get(target, prop, receiver) {
if (secondObject.hasOwnProperty(prop)) return secondObject[prop];
return Reflect.get(...arguments);
}
})
}
let t=function namedFunction(a,b,c){return a+b+c;}
console.log(t.name)//read only property
let f=shadow(t,{name:"addition"})
console.log(f.name)

Is it possible to create a function with another prototype than Function.prototype?

I am working on a parser combinator library in JavaScript. For that I want to create functions that can be called like any other functions, but also have member functions that can be called in turn to produce output based on the function they are attached to (e.g. combinators).
I can of course add members to functions like this:
//the functions I want to add additional members to
function hello(x) {
return "Hello " + x;
}
function goodbye(x) {
return "Goodbye " + x;
}
//The function I want as a member of the above functions.
//it creates another function based on the function it is
//attached to.
function double() {
var that = this;
return function(x) {
return that(x) + ", " + that(x);
};
}
//I can attach them manually to the function objects:
hello.double = double;
//calling hello.double()('Joe') results in => "Hello Joe, Hello Joe"
goodbye.double = double;
//calling goodbye.double()('Joe') results in => "Goodbye Joe, Goodbye Joe"
I could create a function that augments all my functions with a double member, but I would have to remember to call it every time I create a Hey, Sayonara, etc. function. Also my greeting functions would have all those members each, directly on the function object, for each instance. I would prefer to put them all in one prototype and make this the prototype of all my greeting functions. The following options don't work either:
replacing hello.__proto__ (nonstandard, won't work in all browsers)
modifiying Function.prototype directly (would add those members to all other functions as well, but they do not make sense there - I only want to call double on a set of my own functions)
Is it even possible to give a function object a custom prototype or am I stuck with modifying each function object I create?
Update: I changed the above example to be more similar to the actual problem I am working on. This is about modyfing function objects not normal objects. The final goal is to enable a comfortable syntax for parser combinators, e.g. (much simplified):
//parses one argument
var arg = …
//parses one function name
var name = …
//parses a function call, e.g. foo(x+y, "test", a*2)
var functionCall = name.then(elem("(")).then(arg.repSep(",")).then(")").into(process(…))
I want to be able to add members to a set of functions so, when these members are called, they return new functions based on the function on which they were called. This is to be used for parser combinators / monadic parsers.
Yes, you can, using setPrototypeOf.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf.
function prototype() { }
prototype.double = function() { console.log("double"); };
function myfunc() { }
Object.setPrototypeOf(myfunc, prototype);
myfunc.double();
This is essentially the standardized version of __proto__.
There is no other way to directly create a function with a prototype other than Function.prototype. Consider:
function makeFunc() {
return function x() { };
}
function protofunc { }
protofunc.double = { }...
makeFunc.prototype = protofunc;
new makeFunc()
Unfortunately, by returning a function from the makeFunc constructor, rather than the default this, the makeFunc.prototype is not applied.
Or:
myFunc = Object.create(protofunc, ???);
Normally we think of using Object.create to create an object with a prototype, but in this case, there's no way to specify a function as being the object.
Bottom line: the only alternative is to set the prototype explicitly, which you can do either with __proto__, or setPrototypeOf. This is an ES6 feature. Normal browser support caveats apply. See http://kangax.github.io/compat-table/es6/.
Although I know you asked for a solution without using Function.prototype, I wonder whether you had considered that you can chain conditionally-executing behaviors such that a Function.prototype function like double() will allow a co-existence of different behaviors depending on "class" instance...
// This could also be adapted to itself be on Function.prototype
function chainConditions () {
var args = arguments;
return function () {
for (var i=0, argl = args.length; i < argl; i++) {
var ret = args[i].apply(this, arguments);
if (typeof (ret) !== 'undefined') { // If you want to allow undefined to be returnable, you could instead add this to a try-catch and ignore those which throw exceptions or a certain exception
return ret;
}
}
};
}
Function.prototype.double = function () {
if (this.prototype instanceof Salutation) {
var that = this;
return function(x) {
return that(x) + ", " + that(x);
};
}
};
Function.prototype.double = chainConditions(
function () {
if (this.prototype instanceof Tennis) {
var that = this;
return function(x) {
return that(x) + ", " + that(x);
};
}
},
Function.prototype.double
);
function Salutation () {}
function Hello(x) {
return "Hello " + x;
}
function Goodbye(x) {
return "Goodbye " + x;
}
Goodbye.prototype = new Salutation();
function Tennis () {
}
function TennisPlayer (x) {
return x + ' serve';
}
TennisPlayer.prototype = new Tennis();
alert(TennisPlayer.double()('Forehand')); // Forehand serve, Forehand serve
alert(Goodbye.double()('Yellow Brick Road')); // Goodbye Yellow Brick Road, Goodbye Yellow Brick Road
alert(Hello.double()('Yellow Brick Road')); // does not work as we did not use Hello.prototype = new Salutation();
One should be able to abstract this even further by allowing one function to be used for the class type checking (e.g., grouping all Salutation methods on the Function.prototype together as one type check), and another to accept a list of methods keyed to their conditional behaviors.
While it uses its own API, it is fairly non-obtrusive and can even be made to work with existing methods on the Function.prototype which do not play along by throwing an exception (just be sure to include any pre-existing methods last).
A couple of different options. I think you should be thinking in terms of objects and inheritance instead of functions and globals. In the example above, you are basically implying you want "world" to inherit the set of hello methods. (Or do you want "hello" to inherit "world"?)
You should start by reading this paper here: http://www.crockford.com/javascript/inheritance.html
Here's some simple code that demonstrates inheritance using "prototypal inheritance"
// ---------------
function inherit (obj, base) {
var tmp = function () { };
tmp.prototype = base.prototype;
obj.prototype = new tmp();
obj.prototype.constructor = obj;
};
function HelloSet() {
;
}
HelloSet.prototype.helloA = function() {
return "Hello A " + this.displayName;
};
HelloSet.prototype.helloB = function() {
return "Hello B " + this.displayName;
};
function World(displayName) {
HelloSet.constructor.call(this); // constructor chaining
this.displayName = displayName;
}
inherit(World, HelloSet); // World now has all the methdods of HelloSet
// ---------------
// now let's create some worlds
var earth = new World("Earth");
var mars = new World("Mars");
earth.helloA(); // returns "Hello A Earth"
mars.helloB(); // returns "Hello B Mars"
A short answer to your question would be: Yes.
function Parent() {
// constructor
}
function Child() {
// constructor
}
Child.prototype = new Parent();
Here's how to add methods to your Child class:
Child.prototype.someMethod = function() {
// do something
}
It's been a long time that I've used Javascript in an object-oriented fashion unfortunately, but I believe there are some solutions to make the syntax a little bit clearer.

Call a JavaScript function name using a string?

How can I hook up an event to a function name I have defined as a string?
I'm using Prototype.js, although this is not Prototype-speficic.
$(inputId).observe('click', formData.fields[x].onclick);
This would result in JavaScript complaining that my handler is not a function. I would prefer not us use eval().
Property accessors can be used to access any object's properties or functions.
If the function is in the global scope, you can get it using the window object:
var myFunc = window[myFuncName];
This also works within the this scope:
var myFunc = this[myFuncName];
I have worked on this problem, as I needed a function like this. Here is my sandbox code, not thoroughly tested, but can be a startpoint for others.
Note that there is one eval() in the code as I couldn't figure out how to bypass that step, maybe a javascript quirk and cannot be done in any other way. Let me know if there is a way to get rid of eval() here!
executeFunctionByName = function(functionName)
{
var args = Array.prototype.slice.call(arguments).splice(1);
//debug
console.log('args:', args);
var namespaces = functionName.split(".");
//debug
console.log('namespaces:', namespaces);
var func = namespaces.pop();
//debug
console.log('func:', func);
ns = namespaces.join('.');
//debug
console.log('namespace:', ns);
if(ns == '')
{
ns = 'window';
}
ns = eval(ns);
//debug
console.log('evaled namespace:', ns);
return ns[func].apply(ns, args);
}
core = {
paragraph: {
titlebar: {
user: "ddd",
getUser: function(name)
{
this.user = name;
return this.user;
}
}
}
}
var testf = function()
{
alert('dkdkdkd');
}
var x = executeFunctionByName('core.paragraph.titlebar.getUser', 'Ikon');
executeFunctionByName('testf');
... or this[myFuncName];
Perhaps?
setTimeout ( "myFunc()", 1 );
Just an eval would do the job
var call = eval("method_name").call(args);
Looks like formData.fields[x].onclick holds the name of a global function? If so try:
$(inputId).observe('click', window[formData.fields[x].onclick]);
window.myFunction === window["myFunction"]
Do you know what the onclick property contains or what type it is? I assume this is prototype specific stuff, as "fields" does not exist in DOM forms.
If you need to call a string function with arguments, do this:
window[stringFunctionName].apply( window, arrayOfArguments )
You can use scope in place of window if preferred
update:---
use ES6 export and import
a.js
const fn = {
aaa: function() {
//code
},
bbb: function() {
//code
},
//codes ....
nnn: function() {
//code
}
}
export default fn
b.js
import someFn from './a'
//eg
const str1='aaa'
const str2 = 'bbb'
someFn[str1]()
eval('str') (obsolete feature https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Deprecated_and_obsolete_features )
setTimeout('str') setInterval('str')
window['str'] (but...sometimes,global object is not window)
new Function('str')
These methods above always not be recommend by some reasons, but they are really convenient to use.
These methods below are safe, but really not conveninet to use.
switch...case (or if...else)
switch(str){
case 'str1':
fn1()
break
case 'str2':
fn2
//and so on
}
put functions in a object
const fn={
str1:fn1,
str2:fn2
//and so on
}
fn[str1] //call function

Categories