How do I write a function with extend functionality in javascript? - javascript

I try to realize a function e.g. MyFn() with some features as follows:
1. MyFn('Id') > It must be result the value of document.getElementById('Id');
2. MyFn('Id').MyMethode(); > It must be result the performing of a function.
Below this is realized by means of "Object.prototype" as follows:
Object.prototype.MyFn =function(param1){ return document.getElementById(param1); };
alert( MyFn('mydiv1') );
MyFn('mydiv1').posi = function() { alert("Hello, I'm the function posi!"); };
MyFn('mydiv1').posi();
alert( MyFn('mydiv1') );
Just the above example is what I'm trying to realize. But I don't want to use Object.prototype or jQuery.
Below is my wrong approach (it is maybe helpfully what I'm trying to say or to do):
var MyObj = {
method: function(args, callback) {
if(typeof callback == "function") {
callback();
}
return 123;
}
}
MyFn = function(sId) {
return MyObj;
};
alert( MyFn("mydiv1").method() ); // This is ok, because it calls the method: MyObj.method() as it was expected.
alert( MyFn("mydiv1") ); // <-- But here I like to get document.getElementById("mydiv1").
Note: The syntax of code (how the functions are to call) is important! The functions are to call as follows: MyFn('Element-Id') or MyFn('Element-Id').posi(), but not something as follows: MyObj.MyMethode()
Do you have any idea how can I it realize? Thanks in advance.

You could try something like:
var MyObj = {
method: function(args, callback) {
if(typeof callback == "function") {
callback();
}
return 123;
}
}
var MyFn = function(sId) {
this.elem = document.getElementById(sId);
this.MyObj = MyObj;
return this;
};
alert( MyFn("mydiv1").MyObj.method() );
alert( MyFn("mydiv1").elem );
This returns a reference to the function, after the function executes, so offers syntax much like C# extension methods for example.

Should be rather straight forward, seeing as functions are objects as well.
The way it's usually done, and the way jQuery does it, is to return a new instance of the function, which is done with a simple check
function MyFn(selector, context) {
if ( !(this instanceof MyFn) ) { // not an instance
return new MyFn(arguments); // calls itself with the "new" keyword
} else { // now it is an instance
context = context || document;
this[0] = context.getElementById(id);
}
return this;
}
Now building on that, we can add methods, but that requires prototyping them, which is the correct way to do this anyway
MyFn.prototype.width = function() {
return this[0].style.width;
}
and even make those methods chainable
MyFn.prototype.width = function(width) {
if ( width ) {
this[0].style.width = width + 'px';
return this;
} else {
return this[0].style.width;
}
}
FIDDLE

Ugly, not recomended by almost all design patern, but should work :
MyFn = function(sId) {
var obj = document.getElementById(param1);
obj.method = function(args, callback) {
if(typeof callback == "function") {
callback();
}
return 123;
}
return MyObj;
};
Basicly you add the function manualy to the object.
It's not a good desing patern as someone external won't know in advance that the object has an extra method.

This is a bit hacky solution:
var MyObj = function (id) {
var obj = document.getElementById(id);
// attach functions here
obj.myFun = function () {
// ...
}
// ...
return obj;
}
You get the object, attach your own functions to the object (hopefully without redefining existing ones), then return it.

Related

Call a function from a variable [duplicate]

I have the name of a function in JavaScript as a string. How do I convert that into a function pointer so I can call it later?
Depending on the circumstances, I may need to pass various arguments into the method too.
Some of the functions may take the form of namespace.namespace.function(args[...]).
Don't use eval unless you absolutely, positively have no other choice.
As has been mentioned, using something like this would be the best way to do it:
window["functionName"](arguments);
That, however, will not work with a namespace'd function:
window["My.Namespace.functionName"](arguments); // fail
This is how you would do that:
window["My"]["Namespace"]["functionName"](arguments); // succeeds
In order to make that easier and provide some flexibility, here is a convenience function:
function executeFunctionByName(functionName, context /*, args */) {
var args = Array.prototype.slice.call(arguments, 2);
var namespaces = functionName.split(".");
var func = namespaces.pop();
for(var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
return context[func].apply(context, args);
}
You would call it like so:
executeFunctionByName("My.Namespace.functionName", window, arguments);
Note, you can pass in whatever context you want, so this would do the same as above:
executeFunctionByName("Namespace.functionName", My, arguments);
Just thought I'd post a slightly altered version of Jason Bunting's very helpful function.
First, I have simplified the first statement by supplying a second parameter to slice(). The original version was working fine in all browsers except IE.
Second, I have replaced this with context in the return statement; otherwise, this was always pointing to window when the target function was being executed.
function executeFunctionByName(functionName, context /*, args */) {
var args = Array.prototype.slice.call(arguments, 2);
var namespaces = functionName.split(".");
var func = namespaces.pop();
for (var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
return context[func].apply(context, args);
}
The answer to this other question shows you how to do that: Javascript equivalent of Python's locals()?
Basically, you can say
window["foo"](arg1, arg2);
or as many others have suggested, you can just use eval:
eval(fname)(arg1, arg2);
although this is extremely unsafe unless you're absolutely sure about what you're eval-ing.
I think an elegant way of doing this is by defining your functions in a hash object. Then you can have a reference to those functions from the hash using the string. e.g.
var customObject = {
customFunction: function(param){...}
};
Then you can call:
customObject['customFunction'](param);
Where customFunction will be a string matching a function defined in your object.
UPDATE
It seems that this answer was helpful for many fellow coders out there so here goes an updated version.
With ES6 you can additionally use Computed Property Names which will allow you to avoid magic strings.
const FunctionNames = Object.freeze({
FirstFunction: "firstFunction",
SecondFunction: "secondFunction"
});
...
var customObject = {
[FunctionNames.FirstFunction]: function(param){...},
[FunctionNames.SecondFunction]: function(param){...}
};
...
customObject[FunctionNames.FirstFunction](param);
Could you not just do this:
var codeToExecute = "My.Namespace.functionName()";
var tmpFunc = new Function(codeToExecute);
tmpFunc();
You can also execute any other JavaScript using this method.
With ES6 you could to access class methods by name:
class X {
method1(){
console.log("1");
}
method2(){
this['method1']();
console.log("2");
}
}
let x = new X();
x['method2']();
the output would be:
1
2
Two things:
avoid eval, it's terribly dangerous and slow
secondly it doesn't matter where your function exists, "global" -ness is irrelevant. x.y.foo() can be enabled through x.y['foo']() or x['y']['foo']() or even window['x']['y']['foo'](). You can chain indefinitely like this.
All the answers assume that the functions can be accessed through global scope (window). However, the OP did not make this assumption.
If the functions live in a local scope (aka closure) and are not referenced by some other local object, bad luck: You have to use eval() AFAIK, see
dynamically call local function in javascript
Depending on where you are you can also use:
this["funcname"]();
self["funcname"]();
window["funcname"]();
top["funcname"]();
globalThis["funcname"]();
or, in nodejs
global["funcname"]()
Here is my contribution to Jason Bunting's / Alex Nazarov's excellent answers, where I include error checking requested by Crashalot.
Given this (contrived) preamble:
a = function( args ) {
console.log( 'global func passed:' );
for( var i = 0; i < arguments.length; i++ ) {
console.log( '-> ' + arguments[ i ] );
}
};
ns = {};
ns.a = function( args ) {
console.log( 'namespace func passed:' );
for( var i = 0; i < arguments.length; i++ ) {
console.log( '-> ' + arguments[ i ] );
}
};
name = 'nsa';
n_s_a = [ 'Snowden' ];
noSuchAgency = function(){};
then the following function:
function executeFunctionByName( functionName, context /*, args */ ) {
var args, namespaces, func;
if( typeof functionName === 'undefined' ) { throw 'function name not specified'; }
if( typeof eval( functionName ) !== 'function' ) { throw functionName + ' is not a function'; }
if( typeof context !== 'undefined' ) {
if( typeof context === 'object' && context instanceof Array === false ) {
if( typeof context[ functionName ] !== 'function' ) {
throw context + '.' + functionName + ' is not a function';
}
args = Array.prototype.slice.call( arguments, 2 );
} else {
args = Array.prototype.slice.call( arguments, 1 );
context = window;
}
} else {
context = window;
}
namespaces = functionName.split( "." );
func = namespaces.pop();
for( var i = 0; i < namespaces.length; i++ ) {
context = context[ namespaces[ i ] ];
}
return context[ func ].apply( context, args );
}
will allow you to call a javascript function by name stored in a string, either namespaced or global, with or without arguments (including Array objects), providing feedback on any errors encountered (hopefully catching them).
The sample output shows how it works:
// calling a global function without parms
executeFunctionByName( 'a' );
/* OUTPUT:
global func passed:
*/
// calling a global function passing a number (with implicit window context)
executeFunctionByName( 'a', 123 );
/* OUTPUT:
global func passed:
-> 123
*/
// calling a namespaced function without parms
executeFunctionByName( 'ns.a' );
/* OUTPUT:
namespace func passed:
*/
// calling a namespaced function passing a string literal
executeFunctionByName( 'ns.a', 'No Such Agency!' );
/* OUTPUT:
namespace func passed:
-> No Such Agency!
*/
// calling a namespaced function, with explicit context as separate arg, passing a string literal and array
executeFunctionByName( 'a', ns, 'No Such Agency!', [ 007, 'is the man' ] );
/* OUTPUT:
namespace func passed:
-> No Such Agency!
-> 7,is the man
*/
// calling a global function passing a string variable (with implicit window context)
executeFunctionByName( 'a', name );
/* OUTPUT:
global func passed:
-> nsa
*/
// calling a non-existing function via string literal
executeFunctionByName( 'n_s_a' );
/* OUTPUT:
Uncaught n_s_a is not a function
*/
// calling a non-existing function by string variable
executeFunctionByName( n_s_a );
/* OUTPUT:
Uncaught Snowden is not a function
*/
// calling an existing function with the wrong namespace reference
executeFunctionByName( 'a', {} );
/* OUTPUT:
Uncaught [object Object].a is not a function
*/
// calling no function
executeFunctionByName();
/* OUTPUT:
Uncaught function name not specified
*/
// calling by empty string
executeFunctionByName( '' );
/* OUTPUT:
Uncaught is not a function
*/
// calling an existing global function with a namespace reference
executeFunctionByName( 'noSuchAgency', ns );
/* OUTPUT:
Uncaught [object Object].noSuchAgency is not a function
*/
You just need convert your string to a pointer by window[<method name>].
example:
var function_name = "string";
function_name = window[function_name];
and now you can use it like a pointer.
Here is my Es6 approach which enables you to call your function by it's name as string or it's function name and also enable you to pass different numbers of arguments to different types of functions:
function fnCall(fn, ...args)
{
let func = (typeof fn =="string")?window[fn]:fn;
if (typeof func == "function") func(...args);
else throw new Error(`${fn} is Not a function!`);
}
function example1(arg1){console.log(arg1)}
function example2(arg1, arg2){console.log(arg1 + " and " + arg2)}
function example3(){console.log("No arguments!")}
fnCall("example1", "test_1");
fnCall("example2", "test_2", "test3");
fnCall(example3);
fnCall("example4"); // should raise an error in console
If you want to call a function of an object instead of a global function with window["functionName"]. You can do it like;
var myObject=new Object();
myObject["functionName"](arguments);
Example:
var now=new Date();
now["getFullYear"]()
BE CAREFUL!!!
One should try to avoid calling a function by string in JavaScript for two reasons:
Reason 1: Some code obfuscators will wreck your code as they will change the function names, making the string invalid.
Reason 2: It is much harder to maintain code that uses this methodology as it is much harder to locate usages of the methods called by a string.
Surprised to see no mention of setTimeout.
To run a function without arguments:
var functionWithoutArguments = function(){
console.log("Executing functionWithoutArguments");
}
setTimeout("functionWithoutArguments()", 0);
To run function with arguments:
var functionWithArguments = function(arg1, arg2) {
console.log("Executing functionWithArguments", arg1, arg2);
}
setTimeout("functionWithArguments(10, 20)");
To run deeply namespaced function:
var _very = {
_deeply: {
_defined: {
_function: function(num1, num2) {
console.log("Execution _very _deeply _defined _function : ", num1, num2);
}
}
}
}
setTimeout("_very._deeply._defined._function(40,50)", 0);
I don't think you need complicated intermediate functions or eval or be dependent on global variables like window:
function fun1(arg) {
console.log(arg);
}
function fun2(arg) {
console.log(arg);
}
const operations = {
fun1,
fun2
};
operations["fun1"]("Hello World");
operations.fun2("Hello World");
// You can use intermediate variables, if you like
let temp = "fun1";
operations[temp]("Hello World");
It will also work with imported functions:
// mode.js
export function fun1(arg) {
console.log(arg);
}
export function fun2(arg) {
console.log(arg);
}
// index.js
import { fun1, fun2 } from "./mod";
const operations = {
fun1,
fun2
};
operations["fun1"]("Hello World");
operations["fun2"]("Hello World");
Since it is using property access, it will survive minimization or obfuscation, contrary to some answers you will find here.
So, like others said, definitely the best option is:
window['myfunction'](arguments)
And like Jason Bunting said, it won't work if the name of your function includes an object:
window['myobject.myfunction'](arguments); // won't work
window['myobject']['myfunction'](arguments); // will work
So here's my version of a function that will execute all functions by name (including an object or not):
my = {
code : {
is : {
nice : function(a, b){ alert(a + "," + b); }
}
}
};
guy = function(){ alert('awesome'); }
function executeFunctionByName(str, args)
{
var arr = str.split('.');
var fn = window[ arr[0] ];
for (var i = 1; i < arr.length; i++)
{ fn = fn[ arr[i] ]; }
fn.apply(window, args);
}
executeFunctionByName('my.code.is.nice', ['arg1', 'arg2']);
executeFunctionByName('guy');
let t0 = () => { alert('red0') }
var t1 = () =>{ alert('red1') }
var t2 = () =>{ alert('red2') }
var t3 = () =>{ alert('red3') }
var t4 = () =>{ alert('red4') }
var t5 = () =>{ alert('red5') }
var t6 = () =>{ alert('red6') }
function getSelection(type) {
var evalSelection = {
'title0': t0,
'title1': t1,
'title2': t2,
'title3': t3,
'title4': t4,
'title5': t5,
'title6': t6,
'default': function() {
return 'Default';
}
};
return (evalSelection[type] || evalSelection['default'])();
}
getSelection('title1');
A more OOP solution ...
One more detail on Jason and Alex's posts. I found it helpful to add a default value to context. Just put context = context == undefined? window:context; at the beginning of the function. You can change window to whatever your preferred context is, and then you won't need to pass in the same variable each time you call this in your default context.
To add to Jason Bunting's answer, if you're using nodejs or something (and this works in dom js, too), you could use this instead of window (and remember: eval is evil:
this['fun'+'ctionName']();
There's a very similar thing in my code.
I have a server-generated string which contains a function name which I need to pass as a callback for a 3rd party library. So I have a code that takes the string and returns a "pointer" to the function, or null if it isn't found.
My solution was very similar to "Jason Bunting's very helpful function" *, although it doesn't auto-execute, and the context is always on the window. But this can be easily modified.
Hopefully this will be helpful to someone.
/**
* Converts a string containing a function or object method name to a function pointer.
* #param string func
* #return function
*/
function getFuncFromString(func) {
// if already a function, return
if (typeof func === 'function') return func;
// if string, try to find function or method of object (of "obj.func" format)
if (typeof func === 'string') {
if (!func.length) return null;
var target = window;
var func = func.split('.');
while (func.length) {
var ns = func.shift();
if (typeof target[ns] === 'undefined') return null;
target = target[ns];
}
if (typeof target === 'function') return target;
}
// return null if could not parse
return null;
}
Here's a bit robust and reusable solution I ended up implementing for one of my projects.
A FunctionExecutor Constructor Function
Usage:
let executor = new FunctionExecutor();
executor.addFunction(two)
executor.addFunction(three)
executor.execute("one");
executor.execute("three");
Obviously in the project the adding of all the functions that required to be called by name was done by a loop.
The function Executor:
function FunctionExecutor() {
this.functions = {};
this.addFunction = function (fn) {
let fnName = fn.name;
this.functions[fnName] = fn;
}
this.execute = function execute(fnName, ...args) {
if (fnName in this.functions && typeof this.functions[fnName] === "function") {
return this.functions[fnName](...args);
}
else {
console.log("could not find " + fnName + " function");
}
}
this.logFunctions = function () {
console.log(this.functions);
}
}
Example Usage:
function two() {
console.log("two");
}
function three() {
console.log("three");
}
let executor = new FunctionExecutor();
executor.addFunction(two)
executor.addFunction(three)
executor.execute("one");
executor.execute("three");
There too some very helpful way.
http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx
var arrayMaker = {
someProperty: 'some value here',
make: function (arg1, arg2) {
return [ this, arg1, arg2 ];
},
execute: function_name
};
I can't resist mentioning another trick, which helps if you have an unknown number of arguments that are also being passed as part of the string containing the function name. For example:
var annoyingstring = 'call_my_func(123, true, "blah")';
If your Javascript is running on a HTML page, all you need is an invisible link; you can pass a string into the onclick attribute, and the call the click method.
<!-- invisible -->
$('#link_secret').attr('onclick', annoyingstring);
$('#link_secret').click();
Or create the <a> element at runtime.
Easiest way is to access it like has element
window.ClientSideValidations.forms.location_form
is same as
window.ClientSideValidations.forms['location_form']
People keep saying that eval is dangerous and evil because it can run any arbitrary code. However, if you use eval with a whitelisting approach, assuming you know all the possible function names that may need to be run in advance, then eval is no longer a security concern because the input is no longer arbitrary. Whitelisting is a good and frequent security pattern. Here's an example:
function runDynamicFn(fnName, ...args) {
// can also be fed from a tightly controlled config
const allowedFnNames = ['fn1', 'ns1.ns2.fn3', 'ns4.fn4'];
return allowedFnNames.includes(fnName) ? eval(fnName)(...args) : undefined;
}
// test function:
function fn1(a) {
console.log('fn1 called with', a)
}
runDynamicFn('alert("got you!")')
runDynamicFn('fn1', 'foo')
Look basic:
var namefunction = 'jspure'; // String
function jspure(msg1 = '', msg2 = '') {
console.log(msg1+(msg2!=''?'/'+msg2:''));
} // multiple argument
// Results ur test
window[namefunction]('hello','hello again'); // something...
eval[namefunction] = 'hello'; // use string or something, but its eval just one argument and not exist multiple
Exist other type function is class and look example nils petersohn
Thanks for the very helpful answer. I'm using Jason Bunting's function in my projects.
I extended it to use it with an optional timeout, because the normal way to set a timeout wont work. See abhishekisnot's question
function executeFunctionByName(functionName, context, timeout /*, args */ ) {
var args = Array.prototype.slice.call(arguments, 3);
var namespaces = functionName.split(".");
var func = namespaces.pop();
for (var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
var timeoutID = setTimeout(
function(){ context[func].apply(context, args)},
timeout
);
return timeoutID;
}
var _very = {
_deeply: {
_defined: {
_function: function(num1, num2) {
console.log("Execution _very _deeply _defined _function : ", num1, num2);
}
}
}
}
console.log('now wait')
executeFunctionByName("_very._deeply._defined._function", window, 2000, 40, 50 );
There are several executeByName functions here which works fine, unless name contains square brackets - issue I ran into - as I have dynamically generated names. So above functions will fail on names like
app.widget['872LfCHc']['toggleFolders']
As a remedy, I've made function to take this into account too, maybe someone will find it usefull:
Generated from CoffeeScript:
var executeByName = function(name, context) {
var args, func, i, j, k, len, len1, n, normalizedName, ns;
if (context == null) {
context = window;
}
args = Array.prototype.slice.call(arguments, 2);
normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.');
ns = normalizedName.split(".");
func = context;
for (i = j = 0, len = ns.length; j < len; i = ++j) {
n = ns[i];
func = func[n];
}
ns.pop();
for (i = k = 0, len1 = ns.length; k < len1; i = ++k) {
n = ns[i];
context = context[n];
}
if (typeof func !== 'function') {
throw new TypeError('Cannot execute function ' + name);
}
return func.apply(context, args);
}
For better readability check also CoffeeScript version:
executeByName = (name, context = window) ->
args = Array.prototype.slice.call(arguments, 2)
normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.')
ns = normalizedName.split "."
func = context
for n, i in ns
func = func[n]
ns.pop()
for n, i in ns
context = context[n];
if typeof func != 'function'
throw new TypeError 'Cannot execute function ' + name
func.apply(context, args)
You can call javascript function within the eval("functionname as string") either. Like below: (eval is pure javascript function)
function testfunc(){
return "hello world";
}
$( document ).ready(function() {
$("div").html(eval("testfunc"));
});
Working example: https://jsfiddle.net/suatatan/24ms0fna/4/

Is it possible to use a function parameter as part of a jquery statement [duplicate]

I have the name of a function in JavaScript as a string. How do I convert that into a function pointer so I can call it later?
Depending on the circumstances, I may need to pass various arguments into the method too.
Some of the functions may take the form of namespace.namespace.function(args[...]).
Don't use eval unless you absolutely, positively have no other choice.
As has been mentioned, using something like this would be the best way to do it:
window["functionName"](arguments);
That, however, will not work with a namespace'd function:
window["My.Namespace.functionName"](arguments); // fail
This is how you would do that:
window["My"]["Namespace"]["functionName"](arguments); // succeeds
In order to make that easier and provide some flexibility, here is a convenience function:
function executeFunctionByName(functionName, context /*, args */) {
var args = Array.prototype.slice.call(arguments, 2);
var namespaces = functionName.split(".");
var func = namespaces.pop();
for(var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
return context[func].apply(context, args);
}
You would call it like so:
executeFunctionByName("My.Namespace.functionName", window, arguments);
Note, you can pass in whatever context you want, so this would do the same as above:
executeFunctionByName("Namespace.functionName", My, arguments);
Just thought I'd post a slightly altered version of Jason Bunting's very helpful function.
First, I have simplified the first statement by supplying a second parameter to slice(). The original version was working fine in all browsers except IE.
Second, I have replaced this with context in the return statement; otherwise, this was always pointing to window when the target function was being executed.
function executeFunctionByName(functionName, context /*, args */) {
var args = Array.prototype.slice.call(arguments, 2);
var namespaces = functionName.split(".");
var func = namespaces.pop();
for (var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
return context[func].apply(context, args);
}
The answer to this other question shows you how to do that: Javascript equivalent of Python's locals()?
Basically, you can say
window["foo"](arg1, arg2);
or as many others have suggested, you can just use eval:
eval(fname)(arg1, arg2);
although this is extremely unsafe unless you're absolutely sure about what you're eval-ing.
I think an elegant way of doing this is by defining your functions in a hash object. Then you can have a reference to those functions from the hash using the string. e.g.
var customObject = {
customFunction: function(param){...}
};
Then you can call:
customObject['customFunction'](param);
Where customFunction will be a string matching a function defined in your object.
UPDATE
It seems that this answer was helpful for many fellow coders out there so here goes an updated version.
With ES6 you can additionally use Computed Property Names which will allow you to avoid magic strings.
const FunctionNames = Object.freeze({
FirstFunction: "firstFunction",
SecondFunction: "secondFunction"
});
...
var customObject = {
[FunctionNames.FirstFunction]: function(param){...},
[FunctionNames.SecondFunction]: function(param){...}
};
...
customObject[FunctionNames.FirstFunction](param);
Could you not just do this:
var codeToExecute = "My.Namespace.functionName()";
var tmpFunc = new Function(codeToExecute);
tmpFunc();
You can also execute any other JavaScript using this method.
With ES6 you could to access class methods by name:
class X {
method1(){
console.log("1");
}
method2(){
this['method1']();
console.log("2");
}
}
let x = new X();
x['method2']();
the output would be:
1
2
Two things:
avoid eval, it's terribly dangerous and slow
secondly it doesn't matter where your function exists, "global" -ness is irrelevant. x.y.foo() can be enabled through x.y['foo']() or x['y']['foo']() or even window['x']['y']['foo'](). You can chain indefinitely like this.
All the answers assume that the functions can be accessed through global scope (window). However, the OP did not make this assumption.
If the functions live in a local scope (aka closure) and are not referenced by some other local object, bad luck: You have to use eval() AFAIK, see
dynamically call local function in javascript
Depending on where you are you can also use:
this["funcname"]();
self["funcname"]();
window["funcname"]();
top["funcname"]();
globalThis["funcname"]();
or, in nodejs
global["funcname"]()
Here is my contribution to Jason Bunting's / Alex Nazarov's excellent answers, where I include error checking requested by Crashalot.
Given this (contrived) preamble:
a = function( args ) {
console.log( 'global func passed:' );
for( var i = 0; i < arguments.length; i++ ) {
console.log( '-> ' + arguments[ i ] );
}
};
ns = {};
ns.a = function( args ) {
console.log( 'namespace func passed:' );
for( var i = 0; i < arguments.length; i++ ) {
console.log( '-> ' + arguments[ i ] );
}
};
name = 'nsa';
n_s_a = [ 'Snowden' ];
noSuchAgency = function(){};
then the following function:
function executeFunctionByName( functionName, context /*, args */ ) {
var args, namespaces, func;
if( typeof functionName === 'undefined' ) { throw 'function name not specified'; }
if( typeof eval( functionName ) !== 'function' ) { throw functionName + ' is not a function'; }
if( typeof context !== 'undefined' ) {
if( typeof context === 'object' && context instanceof Array === false ) {
if( typeof context[ functionName ] !== 'function' ) {
throw context + '.' + functionName + ' is not a function';
}
args = Array.prototype.slice.call( arguments, 2 );
} else {
args = Array.prototype.slice.call( arguments, 1 );
context = window;
}
} else {
context = window;
}
namespaces = functionName.split( "." );
func = namespaces.pop();
for( var i = 0; i < namespaces.length; i++ ) {
context = context[ namespaces[ i ] ];
}
return context[ func ].apply( context, args );
}
will allow you to call a javascript function by name stored in a string, either namespaced or global, with or without arguments (including Array objects), providing feedback on any errors encountered (hopefully catching them).
The sample output shows how it works:
// calling a global function without parms
executeFunctionByName( 'a' );
/* OUTPUT:
global func passed:
*/
// calling a global function passing a number (with implicit window context)
executeFunctionByName( 'a', 123 );
/* OUTPUT:
global func passed:
-> 123
*/
// calling a namespaced function without parms
executeFunctionByName( 'ns.a' );
/* OUTPUT:
namespace func passed:
*/
// calling a namespaced function passing a string literal
executeFunctionByName( 'ns.a', 'No Such Agency!' );
/* OUTPUT:
namespace func passed:
-> No Such Agency!
*/
// calling a namespaced function, with explicit context as separate arg, passing a string literal and array
executeFunctionByName( 'a', ns, 'No Such Agency!', [ 007, 'is the man' ] );
/* OUTPUT:
namespace func passed:
-> No Such Agency!
-> 7,is the man
*/
// calling a global function passing a string variable (with implicit window context)
executeFunctionByName( 'a', name );
/* OUTPUT:
global func passed:
-> nsa
*/
// calling a non-existing function via string literal
executeFunctionByName( 'n_s_a' );
/* OUTPUT:
Uncaught n_s_a is not a function
*/
// calling a non-existing function by string variable
executeFunctionByName( n_s_a );
/* OUTPUT:
Uncaught Snowden is not a function
*/
// calling an existing function with the wrong namespace reference
executeFunctionByName( 'a', {} );
/* OUTPUT:
Uncaught [object Object].a is not a function
*/
// calling no function
executeFunctionByName();
/* OUTPUT:
Uncaught function name not specified
*/
// calling by empty string
executeFunctionByName( '' );
/* OUTPUT:
Uncaught is not a function
*/
// calling an existing global function with a namespace reference
executeFunctionByName( 'noSuchAgency', ns );
/* OUTPUT:
Uncaught [object Object].noSuchAgency is not a function
*/
You just need convert your string to a pointer by window[<method name>].
example:
var function_name = "string";
function_name = window[function_name];
and now you can use it like a pointer.
Here is my Es6 approach which enables you to call your function by it's name as string or it's function name and also enable you to pass different numbers of arguments to different types of functions:
function fnCall(fn, ...args)
{
let func = (typeof fn =="string")?window[fn]:fn;
if (typeof func == "function") func(...args);
else throw new Error(`${fn} is Not a function!`);
}
function example1(arg1){console.log(arg1)}
function example2(arg1, arg2){console.log(arg1 + " and " + arg2)}
function example3(){console.log("No arguments!")}
fnCall("example1", "test_1");
fnCall("example2", "test_2", "test3");
fnCall(example3);
fnCall("example4"); // should raise an error in console
If you want to call a function of an object instead of a global function with window["functionName"]. You can do it like;
var myObject=new Object();
myObject["functionName"](arguments);
Example:
var now=new Date();
now["getFullYear"]()
BE CAREFUL!!!
One should try to avoid calling a function by string in JavaScript for two reasons:
Reason 1: Some code obfuscators will wreck your code as they will change the function names, making the string invalid.
Reason 2: It is much harder to maintain code that uses this methodology as it is much harder to locate usages of the methods called by a string.
Surprised to see no mention of setTimeout.
To run a function without arguments:
var functionWithoutArguments = function(){
console.log("Executing functionWithoutArguments");
}
setTimeout("functionWithoutArguments()", 0);
To run function with arguments:
var functionWithArguments = function(arg1, arg2) {
console.log("Executing functionWithArguments", arg1, arg2);
}
setTimeout("functionWithArguments(10, 20)");
To run deeply namespaced function:
var _very = {
_deeply: {
_defined: {
_function: function(num1, num2) {
console.log("Execution _very _deeply _defined _function : ", num1, num2);
}
}
}
}
setTimeout("_very._deeply._defined._function(40,50)", 0);
I don't think you need complicated intermediate functions or eval or be dependent on global variables like window:
function fun1(arg) {
console.log(arg);
}
function fun2(arg) {
console.log(arg);
}
const operations = {
fun1,
fun2
};
operations["fun1"]("Hello World");
operations.fun2("Hello World");
// You can use intermediate variables, if you like
let temp = "fun1";
operations[temp]("Hello World");
It will also work with imported functions:
// mode.js
export function fun1(arg) {
console.log(arg);
}
export function fun2(arg) {
console.log(arg);
}
// index.js
import { fun1, fun2 } from "./mod";
const operations = {
fun1,
fun2
};
operations["fun1"]("Hello World");
operations["fun2"]("Hello World");
Since it is using property access, it will survive minimization or obfuscation, contrary to some answers you will find here.
So, like others said, definitely the best option is:
window['myfunction'](arguments)
And like Jason Bunting said, it won't work if the name of your function includes an object:
window['myobject.myfunction'](arguments); // won't work
window['myobject']['myfunction'](arguments); // will work
So here's my version of a function that will execute all functions by name (including an object or not):
my = {
code : {
is : {
nice : function(a, b){ alert(a + "," + b); }
}
}
};
guy = function(){ alert('awesome'); }
function executeFunctionByName(str, args)
{
var arr = str.split('.');
var fn = window[ arr[0] ];
for (var i = 1; i < arr.length; i++)
{ fn = fn[ arr[i] ]; }
fn.apply(window, args);
}
executeFunctionByName('my.code.is.nice', ['arg1', 'arg2']);
executeFunctionByName('guy');
let t0 = () => { alert('red0') }
var t1 = () =>{ alert('red1') }
var t2 = () =>{ alert('red2') }
var t3 = () =>{ alert('red3') }
var t4 = () =>{ alert('red4') }
var t5 = () =>{ alert('red5') }
var t6 = () =>{ alert('red6') }
function getSelection(type) {
var evalSelection = {
'title0': t0,
'title1': t1,
'title2': t2,
'title3': t3,
'title4': t4,
'title5': t5,
'title6': t6,
'default': function() {
return 'Default';
}
};
return (evalSelection[type] || evalSelection['default'])();
}
getSelection('title1');
A more OOP solution ...
One more detail on Jason and Alex's posts. I found it helpful to add a default value to context. Just put context = context == undefined? window:context; at the beginning of the function. You can change window to whatever your preferred context is, and then you won't need to pass in the same variable each time you call this in your default context.
To add to Jason Bunting's answer, if you're using nodejs or something (and this works in dom js, too), you could use this instead of window (and remember: eval is evil:
this['fun'+'ctionName']();
There's a very similar thing in my code.
I have a server-generated string which contains a function name which I need to pass as a callback for a 3rd party library. So I have a code that takes the string and returns a "pointer" to the function, or null if it isn't found.
My solution was very similar to "Jason Bunting's very helpful function" *, although it doesn't auto-execute, and the context is always on the window. But this can be easily modified.
Hopefully this will be helpful to someone.
/**
* Converts a string containing a function or object method name to a function pointer.
* #param string func
* #return function
*/
function getFuncFromString(func) {
// if already a function, return
if (typeof func === 'function') return func;
// if string, try to find function or method of object (of "obj.func" format)
if (typeof func === 'string') {
if (!func.length) return null;
var target = window;
var func = func.split('.');
while (func.length) {
var ns = func.shift();
if (typeof target[ns] === 'undefined') return null;
target = target[ns];
}
if (typeof target === 'function') return target;
}
// return null if could not parse
return null;
}
Here's a bit robust and reusable solution I ended up implementing for one of my projects.
A FunctionExecutor Constructor Function
Usage:
let executor = new FunctionExecutor();
executor.addFunction(two)
executor.addFunction(three)
executor.execute("one");
executor.execute("three");
Obviously in the project the adding of all the functions that required to be called by name was done by a loop.
The function Executor:
function FunctionExecutor() {
this.functions = {};
this.addFunction = function (fn) {
let fnName = fn.name;
this.functions[fnName] = fn;
}
this.execute = function execute(fnName, ...args) {
if (fnName in this.functions && typeof this.functions[fnName] === "function") {
return this.functions[fnName](...args);
}
else {
console.log("could not find " + fnName + " function");
}
}
this.logFunctions = function () {
console.log(this.functions);
}
}
Example Usage:
function two() {
console.log("two");
}
function three() {
console.log("three");
}
let executor = new FunctionExecutor();
executor.addFunction(two)
executor.addFunction(three)
executor.execute("one");
executor.execute("three");
There too some very helpful way.
http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx
var arrayMaker = {
someProperty: 'some value here',
make: function (arg1, arg2) {
return [ this, arg1, arg2 ];
},
execute: function_name
};
I can't resist mentioning another trick, which helps if you have an unknown number of arguments that are also being passed as part of the string containing the function name. For example:
var annoyingstring = 'call_my_func(123, true, "blah")';
If your Javascript is running on a HTML page, all you need is an invisible link; you can pass a string into the onclick attribute, and the call the click method.
<!-- invisible -->
$('#link_secret').attr('onclick', annoyingstring);
$('#link_secret').click();
Or create the <a> element at runtime.
Easiest way is to access it like has element
window.ClientSideValidations.forms.location_form
is same as
window.ClientSideValidations.forms['location_form']
People keep saying that eval is dangerous and evil because it can run any arbitrary code. However, if you use eval with a whitelisting approach, assuming you know all the possible function names that may need to be run in advance, then eval is no longer a security concern because the input is no longer arbitrary. Whitelisting is a good and frequent security pattern. Here's an example:
function runDynamicFn(fnName, ...args) {
// can also be fed from a tightly controlled config
const allowedFnNames = ['fn1', 'ns1.ns2.fn3', 'ns4.fn4'];
return allowedFnNames.includes(fnName) ? eval(fnName)(...args) : undefined;
}
// test function:
function fn1(a) {
console.log('fn1 called with', a)
}
runDynamicFn('alert("got you!")')
runDynamicFn('fn1', 'foo')
Look basic:
var namefunction = 'jspure'; // String
function jspure(msg1 = '', msg2 = '') {
console.log(msg1+(msg2!=''?'/'+msg2:''));
} // multiple argument
// Results ur test
window[namefunction]('hello','hello again'); // something...
eval[namefunction] = 'hello'; // use string or something, but its eval just one argument and not exist multiple
Exist other type function is class and look example nils petersohn
Thanks for the very helpful answer. I'm using Jason Bunting's function in my projects.
I extended it to use it with an optional timeout, because the normal way to set a timeout wont work. See abhishekisnot's question
function executeFunctionByName(functionName, context, timeout /*, args */ ) {
var args = Array.prototype.slice.call(arguments, 3);
var namespaces = functionName.split(".");
var func = namespaces.pop();
for (var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
var timeoutID = setTimeout(
function(){ context[func].apply(context, args)},
timeout
);
return timeoutID;
}
var _very = {
_deeply: {
_defined: {
_function: function(num1, num2) {
console.log("Execution _very _deeply _defined _function : ", num1, num2);
}
}
}
}
console.log('now wait')
executeFunctionByName("_very._deeply._defined._function", window, 2000, 40, 50 );
There are several executeByName functions here which works fine, unless name contains square brackets - issue I ran into - as I have dynamically generated names. So above functions will fail on names like
app.widget['872LfCHc']['toggleFolders']
As a remedy, I've made function to take this into account too, maybe someone will find it usefull:
Generated from CoffeeScript:
var executeByName = function(name, context) {
var args, func, i, j, k, len, len1, n, normalizedName, ns;
if (context == null) {
context = window;
}
args = Array.prototype.slice.call(arguments, 2);
normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.');
ns = normalizedName.split(".");
func = context;
for (i = j = 0, len = ns.length; j < len; i = ++j) {
n = ns[i];
func = func[n];
}
ns.pop();
for (i = k = 0, len1 = ns.length; k < len1; i = ++k) {
n = ns[i];
context = context[n];
}
if (typeof func !== 'function') {
throw new TypeError('Cannot execute function ' + name);
}
return func.apply(context, args);
}
For better readability check also CoffeeScript version:
executeByName = (name, context = window) ->
args = Array.prototype.slice.call(arguments, 2)
normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.')
ns = normalizedName.split "."
func = context
for n, i in ns
func = func[n]
ns.pop()
for n, i in ns
context = context[n];
if typeof func != 'function'
throw new TypeError 'Cannot execute function ' + name
func.apply(context, args)
You can call javascript function within the eval("functionname as string") either. Like below: (eval is pure javascript function)
function testfunc(){
return "hello world";
}
$( document ).ready(function() {
$("div").html(eval("testfunc"));
});
Working example: https://jsfiddle.net/suatatan/24ms0fna/4/

How can I reference a closure using a string the same way I do it with a member function without using eval?

We have some js code splitted in many files. We have a core file that defines code used by many other js files.
Currently we have something like this:
core.js:
window.mycore = function() {
var myfunction1 = function() {
};
var myfunction2 = function() {
};
var myfunction3 = function() {
//..
var a = myfunction1(b);
//..
};
//...
// many "myfunction"
//...
var myfunctionN = function() {
};
var publish = function() {
for(var i = 0; i < arguments.length; i++) {
try {
window.mycore[arguments[i]] = eval('(' + arguments[i] + ')');
}
catch(e) {
Log.err(600, arguments[i], e);
}
}
};
publish("myfunction1", "myfunction7", "myfunction8",/*...*/"myfunctionM")
}
app.js:
// ...
// ...
var result = window.core.myfunction1("myparam");
// ...
// ...
Note that none core methods are declared as members of the window.core object. Instead they are attached to the core object with the publish function.
This has some pros:
The core code can reference any core function without the need of writing "window.core."
We avoid writing "var myfunction = window.mycore.myfunction = function() ..." in every public function declaration
The exposed methods can be seen centraliced.
But, the use of eval in the publish function is bringing us problems when using code analysis tools since they don't tend to understand eval declarations.
So, here is my question.
Which is the better way to improve this code, so we can keep the advantages mentioned but eradicating the eval declaration.
I am aware of the solution of sending to the publish function some name/value pairs like publish({'myfunction1': myfunction1}, ... ), but I also want to avoid function name repetitions.
Consider that I am not looking for radical changes since there is a lot of code written already.
Thanks!
I'm not sure I understand completely your reasons for using the "publish" method, but is there any reason your not just returning an object with the correct functions from your constructor?
ie:
window.mycore = (function() {
var myFunc1 = function(a) {
alert(a);
};
var myFunc2 = function(b) {
// call to other function in the same scope
myFunc1(b);
}
...
// at the end just expose the public members you want
return {
myFunc1: myFunc1,
myFunc2: myFunc2
};
})();
or
window.mycore = (function() {
return {
myFunc1: function(a) {
alert(a);
},
myFunc2: function(b) {
this.myFunc1(b);
}
};
})();
or, yet another way to end up with the same object :) ... as always there are different ways to get there
(function(){
var o = {};
o.func1 = function(a) {
alert(a);
}
o.func2 = function(b) {
this.func1(b);
}
window.mycore = o;
})();
So, at a fundamental level, I think it would have benefitted you to have written those name spaces as objects. But thats a whole different subject entirely. (and it disqualifies based on the fact that you dont want to do a lot of refactoring).
With that said, my first idea was that you could probably sidestep the need for eval by using the .call() or .apply() method. What they allow you to do is to chain a function call out of your function name. but that doesn't apply to a "string" which is what you're giving your publish function.
so after googling, this is how you execute a function from a string:
var fn = window[settings.functionName];
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
https://stackoverflow.com/a/912642/680578
Personally I prefer the #Jaime approach, but maybe you may do something like
window.mycore = function() {
function myfunction1() {
};
function myfunction2() {
};
function myfunction3() {
//..
var a = myfunction1(b);
//..
};
//...
// many "myfunction"
//...
function myfunctionN() {
};
var publish = function() {
for(var i = 0; i < arguments.length; i++) {
try {
window.mycore[arguments[i].name] = arguments[i];
}
catch(e) {
Log.err(600, arguments[i].name, e);
}
}
};
publish(myfunction1, myfunction7, myfunction8,/*...*/myfunctionM);
}

Javascript call nested function

I have the following piece of code:
function initValidation()
{
// irrelevant code here
function validate(_block){
// code here
}
}
Is there any way I can call the validate() function outside the initValidation() function? I've tried calling validate() but I think it's only visible inside the parent function.
function initValidation()
{
// irrelevant code here
function validate(_block){
console.log( "test", _block );
}
initValidation.validate = validate;
}
initValidation();
initValidation.validate( "hello" );
//test hello
Hope that you are looking for something like this
function initValidation()
{
// irrelevant code here
this.validate = function(_block){
// code here
}
}
var fCall = new initValidation()
fCall.validate(param);
This will work.
Hope this addresses your problem.
You can call validate from within initValidation. Like this.
function initValidation()
{
// irrelevant code here
function validate(_block){
// code here
}
return validate(someVar);
}
validate is not visible to anything outside of initValidation because of its scope.
Edit: Here's my suggestion of a solution.
(function() {
function validate(_block){
// code here
}
function initValidation()
{
// irrelevant code here
return validate(someVar);
}
function otherFunctions() {
// ...
}
// initValidation = function
}());
// initValidation = undefined
All of your functions will be hidden to anything outside the function wrapper but can all see each other.
This invocation will return function statement, which is function validate.
So you can invoke directly after the first invocation.
function initValidation() {
// irrelevant code here
return function validate(_block) {
// code here
}
}
initValidation()();
I know this is an old post but if you wish to create a set of instances that you wish to work with that reuse the code you could do something like this:
"use strict";
// this is derived from several posts here on SO and ultimately John Resig
function makeClassStrict() {
var isInternal, instance;
var constructor = function(args) {
if (this instanceof constructor) {
if (typeof this.init == "function") {
this.init.apply(this, isInternal ? args : arguments);
}
} else {
isInternal = true;
instance = new constructor(arguments);
isInternal = false;
return instance;
}
};
return constructor;
}
var MyClass = makeClassStrict();// create "class"
MyClass.prototype.init = function(employeeName, isWorking) {
var defaultName = 'notbob';
this.name = employeeName ? employeeName : defaultName;
this.working = !!isWorking;
this.internalValidate = function() {
return {
"check": this.working,
"who": this.name
};
};
};
MyClass.prototype.getName = function() {
return this.name
};
MyClass.prototype.protoValidate = function() {
return {
"check": this.working,
"who": this.name
};
};
var instanceBob = MyClass("Bob", true);// create instance
var instanceFred = MyClass("Fred", false);// create instance
var mything = instanceFred.internalValidate();// call instance function
console.log(mything.check + ":" + mything.who);
var myBobthing = instanceBob.protoValidate();
console.log(myBobthing.check + ":" + myBobthing.who);
I know this thread's been here for quite some time but I thought I'd also leave my 0.02$ on how to call inner functions from outside their scope (might benefit somebody).
Note that in any place, a better design decision should be taken into consideration rather than some hackish workaround which will bite you back later.
How about using function expressions instead of function statements and making use of the global scope.
var innerFn;
function outerFn() {
innerFn = function(number) {
return number ** 2;
}
}
outerFn();
console.log(innerFn(5));
// if there's more complex code around and you could write this defensively
if (typeof innerFn !== 'undefined') {
console.log(`we are squaring the number 5 and the result is: ${innerFn(5)}`);
} else {
console.log('function is undefined');
}
Or, you can make use of closures:
function outer() {
// initialize some parameters, do a bunch of stuff
let x = 5, y = 10;
function inner() {
// keeps references alive to all arguments and parameters in all scopes it references
return `The arithmetic mean of the 2 numbers is: ${(x + y) / 2}`;
}
return inner;
}
innerFn = outer(); // get a reference to the inner function which you can call from outside
console.log(innerFn());
Create a variable outside the parent function, then in the parent function store your required function in the variable.
Var Store;
Function blah() {
Function needed() {
#
}
Store = needed;
}
As a minor variation of Esailija's answer, I did this:
function createTree(somearg) {
function validate(_block) {
console.log( "test", _block );
}
if (somearg==="validate") { return validate; } // for addNodes
// normal invocation code here
validate(somearg);
}
function addNodes() {
const validate = createTree("validate");
//...
validate( "hello" );
}
createTree("create");
addNodes();
//validate("illegal");
so validate() is now perfectly shared between createTree() and addNodes(), and perfectly invisible to the outside world.
Should work.
function initValudation() {
validate();
function validate() {
}
}
Function definition:
function initValidation() {
// code here
function validate(_block){
// code here
console.log(_block);
}
return validate;
}
Call it as below:
initValidation()("hello");
function initValidation()
{
function validate(_block){
console.log(_block)
// code here
}
// you have to call nested function
validate("Its Work")
}
// call initValidation function
initValidation()

adding callback to function - always

I found myself using a weird way to add callback functions to my functions and I was wondering if there is a more generic way to add callbacks to functions, best case I would have a situation where all of my functions check the last given param for being a function and if so use it as a callback.
This is how I did it in the past:
var myFunc = function( obj ) {
if ( arguments.length > 0 ) {
if ( _.util.typeofObj( arguments[arguments.length-1] ) === Function ) {
var callback = arguments[arguments.length-1];
}
}
// some code ...
if ( callback !== undefined ) {
callback();
}
};
var foo = myFunc( myObj, function(){
alert( 'Callback!' );
});
Any suggestions?
I prefer a formal parameter:
var myFunc = function(obj, callback) {
...
}
This way it makes it obvious that there is a callback. You also don't have to mess around with the arguments object; you can just check to see if callback is undefined, and then check to see if it is of the appropriate type (Function).
You could, if you really want to, extend Function.prototype with a .cb prototype. Something like:
Function.prototype.cb = function(cb){
var self = this;
return function(){
self.callback = cb || function(){};
self.apply(self, arguments);
}
}
then your code would compress to:
var myFunc = function(obj){
// some code
this.callback(); // callback will always be defined
}
and the call would slightly change:
myFunc.cb(function(){
// callback code
})(myObj);
Just an idea. You can make the syntax pretty much whatever you want.
Not sure what you are trying to do here, but a way to add a callback that seems more straight forward:
function( obj, callback ) {
if(callback) {
callback();
}
}

Categories