In JavaScript, if I have a string in a variable, is there a way to get a reference to the function object which has that matching name? Note that jQuery is available to me so I can use any of its helper methods also.
For example:
myFunction = function(){};
var func_name = "myFunction";
var myFunctionPtr = ??? //how to get the function from the name
Thanks
if you know that its a global function you can use:
var functPtr = window[func_name];
//functPtr()
Otherwise replace window with the parent object containing the function.
I just did a quick test in Firebug and I was able to get the function from the name by simply eval()ing the name... I feel dirty using eval(), but it seems to get the job done here quite nicely.
var myFunctionPtr = eval(func_name);
This is never a preferred approach. Instead of keeping the function name in func_name, you could have kept the reference to a function just as successfully in something like func_to_call.
If you absolutely require to keep the function reference as a string, you would typically use a hash table to map an arbitrary name to a variable (JS has first-class functions which makes it possible)
myFunction = function(){};
var obj = {func_name: myFunction};
obj['func_name']();//executes the function
Fiddled (I don't know why, it's a such a tiny script :)
It was suggested that you use eval(func_name) - however this could quickly get out of control because of JS scoping.
You have also declared your myFunction = function(){}; as a global variable. On one hand, it lets you reference it as window[func_name] but on the other hand it pollutes the global scope.
this[func_name] should give you the function.
var myfunc = this[func_name];
myfunc();
It depends on where and how the function is (or isn't) declared.
If it's a global and not declared via let name = ... or const name = ... syntax (and it's not a class constructor declared with class), you can check by looking for it as a property on the global object. (Those caveats are all ES2015 things; more below.) You can get a reference to the global object via this in loose mode at global scope; browsers also give you a global called window. So assuming a browser:
if (typeof window[func_name] === "function") {
// ....
}
If it might not be a global, but rather is just in scope because your code closes over it, or if it was created using one of those ES2015 mechanisms I mentioned, there's really no good way to check other than eval:
if (eval("typeof " + func_name) === "function") {
// ....
}
Using eval is a last resort, and you must only use it with strictly-controlled input. But when you have to, and you have strictly-controlled input, it's fine.
About the ES2015 caveats:
The new let, const, and class are very interesting beasties: When used at global scope, they create globals, but they don't create properties on the global object. As of ES2015, although all properties of the global object are globals, not all globals are properties of the global object. It's all part of trying to rein in vastly-polluted global namespace and also bring greater security to the JavaScript binding model. (Now that we have true modules.)
So (note that this will only run in cutting-edge browsers):
// Global scope, in a browser (because I used `window` and `document.body`) that
// implements this aspect of ES2015 (as I write this, Firefox's SpiderMonkey
// doesn't, Chrome's V8 does on the latest Chrome; expect SpiderMonkey and IE
// to catch up pretty quick (didn't test IE Edge, maybe it's already there)
// Strict mode isn't required for this behavior, but for the moment V8 only
// supports the block-scoped constructs in strict mode.
"use strict";
let tbody = setup();
// Old-fashioned var: Creates a property on the global object, so
// we get "function, function"
var f1 = function() { /*...*/ };
result("var declaration", typeof f1, typeof window["f1"]);
// Function declaration: Creates a property on the global object, so
// "function, function"
function f2() {}
result("function declaration", typeof f2, typeof window["f2"]);
// `let` declaration: Doesn't create property on global object, so
// "function, undefined"
let f3 = function() { /*...*/ };
result("let declaration", typeof f3, typeof window["f3"]);
// `const` declaration: Doesn't create property on global object, so
// "function, undefined"
const f4 = function() { /*...*/ };
result("const declaration", typeof f4, typeof window["f4"]);
// `class` declaration: Doesn't create property on global object, so
// "function, undefined"
class C1 {}
result("class declaration", typeof C1, typeof window["C1"]);
function setup() {
document.body.insertAdjacentHTML(
"beforeend",
"<table>" +
"<thead>" +
"<tr><th>test</th><th>global</th><th>prop</th></tr>" +
"</thead>" +
"<tbody></tbody>" +
"</table>"
);
return document.body.querySelector("tbody");
}
function result(label, direct, win) {
tbody.insertAdjacentHTML(
"beforeend",
"<tr><td>" + [label, direct, win].join("</td><td>") + "</td></tr>"
);
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 4px 8px;
}
Output on cutting-edge browsers:
+----------------------+------------+-----------+
| test | global | prop |
+----------------------+------------+-----------+
| var declaration | function | function |
| function declaration | function | function |
| let declaration | function | undefined |
| const declaration | function | undefined |
| class declaration | function | undefined |
+----------------------+------------+-----------+
Note: Some transpilers don't enforce this rigorously, so if you see different results in transpiled code, don't be surprised.
A safe way to do is to sandbox the alleged function while testing its type:
function isFunction(expr) {
function sandboxTemplate() {
var window, document, alert; // etc.
try {
return typeof $expr$ == "function";
} catch (e) {
return false;
}
}
try {
var sandbox = new Function(
sandboxTemplate.toString().replace("$expr$", expr)
+ "return sandboxTemplate()");
return sandbox();
} catch (e) {
return false;
}
}
function test(expr) {
document.write("<div>\"" + expr + "\" <b>is "
+ (isFunction(expr) ? "" : "not ")
+ "</b>a function</div>");
}
/* Let's do some testing */
function realFunction() {
}
test("realFunction"); // exists!
test("notHere"); // non-existent
test("alert('Malicious')"); // attempt to execute malicious code!
test("syntax error {"); // attempt to blow us up!
The output:
"realFunction" is a function
"notHere" is not a function
"alert('Malicious')" is not a function
"syntax error {" is not a function
The sandboxing code could be written in a more concise manner but I like using "template" functions instead of embedding JS code as string literals.
And oh, this does it nicely without using eval -- though one can argue that using a Function constructor is no different than an eval.
Use eval:
myFunction = function(){};
var func_name = "myFunction";
var myFunctionPtr = eval(func_name);
found the function and then call them
autoCallBack : function(_action){
$(".module").each(function(){
var modulName = $(this).attr("id");
if( isFunction(modulName) ){
eval(modulName)();
}
});
}
isFunction : function(_functionName){
try {
eval(_functionName);
} catch (error) {
return false;
}
return true;
}
For NodeJs
Write your functions in a separate file and export them and use with name reference of that to call them, Like
// functions.js
var funcOne = function(){
console.log('function ONE called')
}
module.exports={
// name_exported : internal_name
funcOne : funcOne
}
Use function defined in functions.js in index.js :
// index.js
var methods = require('./functions.js') // path to functions.js
methods['funcOne']()
OUTPUT :
> node index.js
> function ONE called
Related
I have this code and wondering how can we access properties and method of IIFE
var app = (function () {
function app() {
this.name = 'fasf';
}
app.prototype.greeting = function () {
this.a = 'hello world';
console.log(name);
window.alert('hello world');
};
app.prototype.sayhello = function () {
var j = 't';
console.log(this.a);
};
return app;
}());
also about this piece of code
var t = (function greet(name){
name = name || 'enter your name'
console.log('Hello ' + name);
})();
With the code you have, you can just do this:
// create an instance of the app object
var a = new app();
// call methods on it
a.greeting();
a.sayhello();
Your IIFE returns the internal app constructor function and then assigns that to a variable named app. So you can then do new app() to create an instance of that object. Once you create an instance of that object, you can then call any of the methods on the prototype.
In your second IIFE, nothing is returned from the IIFE so t is undefined.
The IIFE itself does not have properties and methods. That's just an immediately invoked function expression. In your first one, it returns a constructor function which is then assigned to a variable so that variable can be used to create objects with that constructor function. There are no properties or methods of the IIFE itself.
The way the IIFE pattern works is that you use local variables for the stuff you want to keep private. Local variables are are only visible inside the function they were defined in they cannot be read or written from anywhere else in the program.
If you want to expose things inside the IIFE outside the IIFE one way to do it is via the return value of the immediately-invoked function:
var stuff = (function(){
// These variables and functions are not
// visible from the outside:
var myvar1 = "Hello";
var myvar2 = "World";
var func1(){
return myvar1 + " " + myvar2;
}
// But we can return a record that contains a
// reference to our private functions, making them
// visible outside this block.
return {
thefunc: func1
}
}());
//Now we can call the "thefunc" function we exported
console.log( stuff.thefunc() );
I made sure to not repeat any variable names to avoid confusion.
In your first example, there isn't much of a point to using the IIFE pattern since there are no local variables that you are making private. You could have just defined the app function outside the IIFE and it would have worked the same.
The second case could have been written more clearly by putting the function in a separate line:
function greet(name){
name = name || 'enter your name'
console.log('Hello ' + name);
}
var t = greet();
Not only is it a bit weird to immediately invoke a named function but in your particular example, the "default argument value" pattern suggests that this function was designed to be called multiple times, sometimes passing the "name" argument and sometimes not passing it (in which case it defaults to the "enter your name" string.
When using IIFE pattern (closure) you usually keep local variables and function private as properly mentions by hugomg's answer.
In case you need to selectively make public some specific property you could consider using "The Revealing Module Pattern" instead, more info here.
Below a simple example showing this pattern:
var app = (function () {
var privateVar = 'hello world';
function sayhelloPrivate() {
console.log(privateVar);
}
function sayhelloPublic() {
console.log(privateVar);
}
// reveal public pointers to
// private functions and properties
return {
sayhello : sayhelloPublic
};
})();
app.sayhello();
//app.sayhelloPrivate(); this will not work as function is private and not visible outside module
I would like to redefine a prototype, but still use the original prototype function. The purpose is to add test bench debug code to an existing production prototype definition.
// production definition
function tester(n) { this.name = n ; }
tester.prototype.getName = function() { return this.name; }
// debug override
if (typeof tester.prototype.getName === 'function') {
var f = tester.prototype.getName;
tester.prototype.getName = function () {
return f() + " (plus some more)";
};
}
// test
var tt = new tester('testing');
console.log(tt.getName()); // logs ' (plus some more)' but I want 'testing (plus some more)'
Naturally, my production prototypes are much more complex, and I would rather not embed my test bench code in the production code.
Many thanks in advance! - John :)
You have to call f with the correct this value and the correct arguments:
f.apply(this, arguments);
Learn more about this and apply.
This seems to be a very fragile approach though because it also requires you to know what kind of value the original method returns and what calling code is doing with it.
But I guess you are only doing this for very specific methods.
In your redefinition, you need to set the proper context (this) for the f function using Function.prototype.apply(). In your code, the context of the f function is set to the global scope, even when it is called in the redefined getName property of tt. Instead, it should be the context of the redefined getName function.
// production definition
function tester(n) { this.name = n ; }
tester.prototype.getName = function() { return this.name; }
// debug override
if (typeof tester.prototype.getName === 'function') {
var f = tester.prototype.getName;
// Here, 'this' is the global scope (window).
console.log('Global scope:');
console.log(this);
console.log('f called with context of global scope:');
console.log(f()); // prints 'name' prop of global scope
tester.prototype.getName = function () {
console.log("Instance:");
console.log(this);
// Here, 'this' is tt when tt.getName() is evaluated.
// If we call f() here, the context for f
// will still be the global scope, instead of tt.
// So, we use apply to set the context of f to
// an instance of tester.
return f.apply(this) + " (plus some more)";
};
}
// test
var tt = new tester('testing');
console.log(tt.getName()); // logs testing (plus some more)'
http://jsfiddle.net/a27xzqc9/3/
Extending Felix and Patrick's answer with encapsulation to avoid using the global variable "f", since I will be reusing this structure several times.
;(function(){
if (typeof tester.prototype.getName === 'function') {
var f = tester.prototype.getName;
tester.prototype.getName = function () {
return f.apply(this) + " (plus some more)";
};
}
})();
Is there a way to get the Function object, while the function is executing?
I am assigning properties to my function, and want to access them. "this" doesn't help. Something like:
a.b=function(){...code...};
a.b.c=100;
I want to access a.b.c from the code in the function, without knowing its own name. "this" refers to a. How can get b?
I tried binding the function to his own object, but I couldn't.
Thank you.
I'm adding this example, I have to repeat after several different "theString" and "someSpecificValues":
Object.defineProperty(theObject, theString, {get: function(...){...}.bind(theObject, someSpecificValues), configurable: true});
You can use a named function expression for this:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.b();
It allows code inside the function to access the function itself, but does not add the identifier to the enclosing scope.
Edit: Here is a more elaborate example of how the name myFunc only exists within the function:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.d = function myFunc() {
console.log(myFunc.c);
};
a.d.c = 300;
a.b(); // logs 100
a.d(); // logs 300
console.log(typeof myFunc); // logs "undefined"
// create a myFunc variable
var myFunc = function() {
console.log("nooooooo!!!!");
};
a.b(); // STILL logs 100. the myFunc variable in this scope
// has no effect on the myFunc name that a.b uses
function callFunc(theFunc) {
theFunc();
}
callFunc(a.d); // STILL logs 300
// ===========================
function returnNamedFunction () {
return function myFunc() {
console.log(myFunc.c);
};
}
var iGotAFunction = returnNamedFunction();
iGotAFunction.c = 700;
iGotAFunction(); // logs 700
In the case when you cannot use a named function expression, e.g. when you are using .bind() on it, then an IIFE will suffice most of the time:
var myObj = {};
myObj.theFunc = (function () {
var f = function (arg1, arg2) {
console.log(this.theProp);
console.log(arg1);
console.log(arg2);
console.log(f.lista);
}.bind(myObj, "A!");
return f;
})();
myObj.theProp = "B!";
myObj.theFunc.lista = [1, 2, 3];
myObj.theFunc("C!");
There are two ways to get current function.
One is "almost deprecated" usage of arguments.callee. In function body it always refers to this function.
var a = {};
a.b = function () {
console.log(arguments.callee.c);
};
a.b.c = 100;
a.b();
arguments.callee is forbidden in strict mode. Reference.
The second one is using named function expression as JLRishe pointed.
arguments.callee pros and cons
Advantages:
it can be safely used with bound functions (arguments.callee refers to bound function)
it can be used with functions created using new Function
Disadvantages:
it can slow your program due to disabling certain optimisations
it's considered as almost deprecated
it can't be used in strict mode
Named function expression pros and cons
Advantages:
it's faster than arguments.callee
it's easier to understand how it works
Disadvantages:
it won't work as expected with bound functions (functionName will refer to original function, not bound one)
it can't be used in functions created with new Function
In a typical js class, all calls to member functions must be preceded by this. I was looking at a technique that would let me create a library of inter-dependent STATIC functions and relying on closure/scope to make things a bit easier.
Example:
var Singleton={
//main entry point
// call with fn name, args...
call:function(){
var args=[];
if (arguments.length==0) {
return;
}
// get the fn name
var fn=arguments[0];
var x;
// make args array
for (x=1;x<arguments.length;x++) {
args[args.length]=arguments[x];
}
// I want to get rid of this part
// See below for what I wish
// Here I have access to fns below due to hoisting in js
// so I put them in a map...
var fns={
test:test
// etc, more like this I do not want to type/maintain
}
// ... all so I can do this
// get my function.
var fun=fns[fn];
// instead of that, I would like to "override whitespace" and
// say something like:
// var fun=['fn_name'];
// so I can index into local scope and get a fn
//
// log error if not found
if (typeof fun=='undefined') {
loge('Singleton: function not found:'+fn);
return;
}
// ok, run the function
return fun.apply(window,args);
// the test fn accesses test2() without dot notation
function test(a){
// Note: here in test fn it can access test2()
// without using this.test2() syntax
// as you would in normal objects
var s=test2();
alert(s+' test:'+a);
};
function test2(){
return 'test2';
};
}
}
I was hoping someone more familiar with advances in javascript might have advice on how to emulate an "implied but unnecessary this", it always struck me as strange that this defaults to window, and wouldn't it be nice if this could be pointed to an anonymous object with the local scope attached.
I would love to say ['localObject'] to get something in scope.
Edit:
After seeing some of the responses, I will restate this in the form of a challenge:
What I am looking for is a syntax cheat, a way to, as #Varuna put it, "1. Access static methods without using this variable i.e. they will remain global to one another. 2. Do not want to maintain a local array for static methods and want to achieve with in the local scope itself."
Put differently, I need to have the declared functions Register themselves, but I don't want to state the function name more than once. I suppose #Varuna has a solution using eval to access the local scope.
The following approach wont work:
var o={};
o['fn']=function fn(){};
o['fn2']=function fn2(){};
...because you have to state the fn name twice, but closure is preserved.
And this:
var a=[
function fn(){}
,function fn2(){}
];
Register(a);
Will not work because, AFAIK, you lose closure, ie. fn2 cannot see fn. Which also makes the following declarative style a "this nightmare":
window.MINE={
fn:function fn(){
//this?
// want to say fn2(), not this.fn2(), nor MINE.fn2()
}
,fn2:function fn2(){
//this?
}
,deeper:{
//more
}
};
But something like this might work, if you created a weird property that does the registration on assignment:
var registar=new Registar();
registar.reg=function fn(){};
registar.reg=function fn2(){};
//then access
var fn=registar.getFn(n);
// or
var fn=registar._[n];
The above relies on js properties and having access to fn.name, which is not available in all cases AFAIK.
If I understand correctly, you want to create objects that:
have static members
... which can be accessed without using the this notation
The easiest solution (assuming I've properly understood your query), would be to simply use a closure to store your stratic fields, access them directly by name, then explicitly add them as object members.
Consider:
var myConstructor = (function(){
var foo = 'someStaticField';
var bar = function(){
alert('A static method returns ' + foo);
};
return function(){
return {
foo : foo,
bar : bar
};
};
})();
var myInstance = new myConstructor();
As per my understanding, you want to:
1. Access static methods without using this variable i.e. they will remain global to one another.
2. Do not want to maintain a local array for static methods and want to achieve with in the local scope itself.
You can check whether a method exist using eval.Check Here
Only drawback is that this will be using eval method.
Code will be:
var Singleton = {
//main entry point
// call with fn name, args...
call: function () {
var args = [];
if (arguments.length == 0) {
return;
}
// get the fn name
var fn = arguments[0];
var x;
// make args array
for (x = 1; x < arguments.length; x++) {
args[args.length] = arguments[x];
}
//check whether function exist in local scope and not in global scope
if (typeof eval(fn) !== 'undefined' && typeof window[fn] === 'undefined') {
// ok, run the function
return eval(fn).apply(window, args);
}
else{
// log error if not found
loge('Singleton: function not found:' + fn);
return;
}
// the test fn accesses test2() without dot notation
function test(a) {
// Note: here in test fn it can access test2()
// without using this.test2() syntax
// as you would in normal objects
var s = test2();
alert(s + ' test:' + a);
};
function test2() {
return 'test2';
};
}
}
How about declaring functions that can access each other in separate closure, and exporting them to main method by binding your call method to an object containing the functions? Something like previous post (modified slightly):
var Singleton = {
call: (function() {
// here 'call' is bound to object containig your test functions
// this: {test, test2}
if (0 == arguments.length) return;
// log error if not found
if ('function' != typeof this[arguments[0]]) {
console.warn('Singleton: function not found:' + arguments[0]);
return;
}
// '...index into local scope and get function
// ie. get the function by it's name
return this[arguments[0]].
apply(window, Array.prototype.slice.call(arguments, 1));
// --- or:
// you can explicitly introduce function names to current scope,
// by `eval`-ing them here (not very much preferred way in JavaScript world):
for (var fname in this)
if (this.hasOwnProperty(fname))
eval('var ' + fname + ' = ' + this[fname]);
// and you can reference them directly by using their names
var fn = eval(arguments[0]);
return fn.apply(window, Array.prototype.slice.call(arguments, 1));
}).bind(
(function() {
var _exports = {};
function test (a) {
var s = test2();
alert(s + ' test: ' + a);
}
function test2 () {
return 'test2';
}
_exports['test'] = test;
_exports['test2'] = test2;
return _exports;
})()
)};
Singleton.call('test', 'foo and stuff');
//
previous post:
You are talking about Function#bind functionality that enables 'customizing' function's context. .bind() your call method to required 'local context' like this:
var Singleton = {
//main entry point
// call with fn name, args...
call: (function() {
// here `this` (context) is object bound to `call` method
// not `global` object, which is default for 'unbound' functions
var locals = this; // {fns, shift, loge, isfunc}
var fn;
var fun;
var x;
if (arguments.length == 0)
return;
// get the fn name
fn = locals.shift(arguments);
// '...index into local scope and get a fn'
fun = locals.fns[fn];
// log error if not found
if (!locals.isfunc(fun)) {
locals.loge('Singleton: function not found:' + fn);
return;
}
// ok, run the function
return fun.apply(window, arguments);
// lock `call`'s context to provided object
// and use `this` to reference it inside `call`
}).bind({
fns: (function(_) {
// and you can '...create a library of inter-dependent STATIC functions'
// in this closure and invoke them in `call` method above
_.test = function (a) {
var s = _.test2();
alert(s + ' test: ' + a);
};
_.test2 = function() {
return 'test2';
};
return _;
})({}),
// and create couple of helper methods as well...
isfunc: (function(_getclass) {
_getclass.func = _getclass(_getclass);
return ('function' !== typeof(/foo/)) ?
function(node) {
return 'function' == typeof node;
} :
function(node) {
return _getclass.func === _getclass(node);
};
})(Function.prototype.call.bind(Object.prototype.toString)),
loge: console.warn,
shift: Function.prototype.call.bind(Array.prototype.shift)
}),
};
Singleton.call('test', 'foo and stuff');
// eof
Here's one 'in your face answer', because I really don't like what I see here.
I don't see why you need this kind of construct, you already have that as part of language core.
1. dynamic lookup
you are doing it in a rather 'unprecedented' kind of way,
hashes already do that for you, and it's lightning fast to do a hash search.
If you are eval()-ing random strings to do simple name lookup you really have to
step aside from a keybord for a while... (no offense please)
2. closures
you are saying about 'using closures' which you actualy don't use.
your call function redeclares test functions each time it gets called,
and looks the ('fresh version') functions in it's own variable scope table,
instead of lookig them up in parent scope chains (aka. closures)
outside it's lexical location
3. nfe vs. nfd
ie. named function expressions vs. named function declarations
...you cannot assign a function to a local var and have it retain closure.
It is a feature, you might not be aware of how it works (it tripped me up as well).
check this article out for clarification
4. exceptions
Singleton: function name not found... x4!
Just go ahead and call a function,
interpreter will throw for you anyway if it cannot find/execute
5. eval (aka. ^^)
Singleton.call.ctx.fun = eval(Singleton.call.ctx.fn);
eval takes any string here(#!), and gladly executes ones like:
'for(;;);', or 'while(1);'... forever.
You probably don't want to have any code running unless it was your stuff.
6. arguments handling
It is considered best practice out there to use single (Object) options parameter
to 'fine tune' any significant piece of bundled functionality,
instead of trying to figure that out by type checking provided argument list
Here's, in couple of simple lines, what I (and as I can see #Jimmy Breck-McKye) suggest you should do:
var Singleton.call = (function () {
var funcmap = {
'f_1': function () {},
// etc.
'f_N': function () {},
};
return function (options) {
// options members:
// context, (Object) context, (defaults to global if none is given)
// func, (String) function_name,
// args, (Array) arguments to pass into a function
// this line does everything your 100+ lines long snippet was trying to:
// look's up parent scope for a function, tries to run it
// passing provided data, throws if it gets stuck.
return funcmap[options.func].apply(options.context, options.args);
};
})();
//
Answering my own question here.
The core of the issue is that you cannot assign a function to a local var and have it retain closure.
Consider that when writing a function with global and window scope, this is not necessary to call another function with identical scope. Such is not the case with member functions.
Another way of saying this is that there is no space where your cursor can sit and as you declare a function it automatically gets attached to the current this.
function fn(){}// if we are in global scope, then window.fn becomes defined
// but if we are inside, say, a constructor, simple declaration will not attach
// it to this, but fn is available in scope.
Any assignment on function declaration BREAKS part of the expected closure:
var IdentifierAvailableToClosure=function Unavailable(){}
But assignment after declaration works:
function NowAvailable(){}
var SynonymAvailableToo=NowAvailable;
This is what I meant by not wanting to repeat the name twice to get the mechanism to work.
This fact made me abandon other methods and rely on eval as suggested. Here is a first draft:
// This object is an encapsulation mechanism for a group of
// inter-dependent, static-ish, functions that can call each other
// without a this pointer prefix.
// Calls take the form of:
// Singleton.call(functionName:String [,arg1]...)
// or
// Singleton.call(contextObject:Object, functionName:String [,arg1]...)
// If a context is not provided, window is used.
//
// This type of mechanism is useful when you have defined a group
// of functions in the window/global scope and they are not ready
// to be formalized into a set of classes, or you have no intention
// of doing that
//
// To illustrate the issue, consider that a function
// which is defined in window/global scope
// does not have to use the this pointer to call a function of
// identical scope -- yet in a class member function, the this pointer
// MUST be used
// Therefore, trying to package such functions requires injecting
// the this pointer into function bodies where calls to associater
// functions are made
//
// Usage is primarily for development where one has control over
// global namespace pollution and the mechanism is useful in
// refactoring prior to formalization of methods into classes
var Singleton={
// Main call point
call:function(){
// Bail with error if no args
if (arguments.length==0) {
throw('Singleton: need at least 1 arg');
}
// As all functions in the local scope library below
// have access to the local scope via closure, we want to reduce
// pollution here, so lets attach locals to this call
// function instead of declaring locals
//
// Prepare to call anon fn
Singleton.call.args=arguments;
// Make ctx have args, context object, and function name
Singleton.call.ctx=(function (){// return args,ctx,name
// out
var args=[];
//locals
var x, fn;
// collapse identifier
var a=Singleton.call.args;
// closure object avail to functions, default to window
that=window;
// first real function argument
var arg_start=1;
// first arg must be function name or object
if (typeof a[0]=='string') {// use window ctx
fn=a[0];
// if first arg is object, second is name
}else if (typeof a[0]=='object') {
// assign given context
that=a[0];
// check second arg for string, function name
if (typeof a[1]!='string') {
var err='Singleton: second argument needs to be a fn name'
+' when first arg is a context object';
throw(err)
return;
}
// ok, have a name
fn=a[1];
// args follow
arg_start=2;
}else{
// improper arg types
var err='Singleton: first argument needs to be a string or object';
throw(err)
}
// build args array for function
for (x=arg_start;x<a.length;x++) {
args[args.length]=a[x];
}
// return context
return {
args: args
,that:that
,fn:fn
};
})();
// using function library present in local scope, try to find specified function
try{
Singleton.call.ctx.fun=eval(Singleton.call.ctx.fn);
}catch (e){
console.error('Singleton: function name not found:' + Singleton.call.ctx.fn);
throw('Singleton: function name not found:' + Singleton.call.ctx.fn);
}
// it must be a function
if (typeof Singleton.call.ctx.fun !== 'function') {
console.error('Singleton: function name not found:' + Singleton.call.ctx.fn);
throw('Singleton: function name not found:' + Singleton.call.ctx.fn);
}
// library functions use that instead of this
// that is visible to them due to closure
var that=Singleton.call.ctx.that;
// Do the call!
return Singleton.call.ctx.fun.apply(that, Singleton.call.ctx.args);
//
// cool library of functions below,
// functions see each other through closure and not through this.fn
function test(s){
alert(test2()+' test:'+s);
}
function info_props(){
console.info(this_props());
}
function test2(){
return 'test2';
}
function this_props(){
var s='';
for (var i in that) {
s+=' '+i;
}
return s;
};
}
};
This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 9 years ago.
I got a string like:
settings.functionName + '(' + t.parentNode.id + ')';
that I want to translate into a function call like so:
clickedOnItem(IdofParent);
This of course will have to be done in JavaScript. When I do an alert on settings.functionName + '(' + t.parentNode.id + ')'; it seems to get everything correct. I just need to call the function that it would translate into.
Legend:
settings.functionName = clickedOnItem
t.parentNode.id = IdofParent
Seeing as I hate eval, and I am not alone:
var fn = window[settings.functionName];
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
Edit: In reply to #Mahan's comment:
In this particular case, settings.functionName would be "clickedOnItem". This would, at runtime translate var fn = window[settings.functionName]; into var fn = window["clickedOnItem"], which would obtain a reference to function clickedOnItem (nodeId) {}. Once we have a reference to a function inside a variable, we can call this function by "calling the variable", i.e. fn(t.parentNode.id), which equals clickedOnItem(t.parentNode.id), which was what the OP wanted.
More full example:
/* Somewhere: */
window.settings = {
/* [..] Other settings */
functionName: 'clickedOnItem'
/* , [..] More settings */
};
/* Later */
function clickedOnItem (nodeId) {
/* Some cool event handling code here */
}
/* Even later */
var fn = window[settings.functionName];
/* note that settings.functionName could also be written
as window.settings.functionName. In this case, we use the fact that window
is the implied scope of global variables. */
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
window[settings.functionName](t.parentNode.id);
No need for an eval()
Here is a more generic way to do the same, while supporting scopes :
// Get function from string, with or without scopes (by Nicolas Gauthier)
window.getFunctionFromString = function(string)
{
var scope = window;
var scopeSplit = string.split('.');
for (i = 0; i < scopeSplit.length - 1; i++)
{
scope = scope[scopeSplit[i]];
if (scope == undefined) return;
}
return scope[scopeSplit[scopeSplit.length - 1]];
}
Hope it can help some people out.
JavaScript has an eval function that evaluates a string and executes it as code:
eval(settings.functionName + '(' + t.parentNode.id + ')');
eval() is the function you need to do that, but I'd advise trying one of these things to minimize the use of eval. Hopefully one of them will make sense to you.
Store the function
Store the function as a function, not as a string, and use it as a function later. Where you actually store the function is up to you.
var funcForLater = clickedOnItem;
// later is now
funcForLater(t.parentNode.id);
or
someObject.funcForLater = clickedOnItem;
// later is now
(someObject.funcForLater)(t.parentNode.id);
Store function name
Even if you have to store the function name as a string, you can minimize complexity by doing
(eval(settings.functionName))(t.parentNode.id);
which minimizes the amount of Javascript you have to construct and eval.
Dictionary of handlers
Put all of the action functions you might need into an object, and call them dictionary-style using the string.
// global
itemActions = { click: clickedOnItem, rightClick: rightClickedOnItem /* etc */ };
// Later...
var actionName = "click"; // Or wherever you got the action name
var actionToDo = itemActions[actionName];
actionToDo(t.parentNode.id);
(Minor note: If instead here you used syntax itemActions[actionName](t.parentNode.id); then the function would be called as a method of itemActions.)
While I like the first answer and I hate eval, I'd like to add that there's another way (similar to eval) so if you can go around it and not use it, you better do. But in some cases you may want to call some javascript code before or after some ajax call and if you have this code in a custom attribute instead of ajax you could use this:
var executeBefore = $(el).attr("data-execute-before-ajax");
if (executeBefore != "") {
var fn = new Function(executeBefore);
fn();
}
Or eventually store this in a function cache if you may need to call it multiple times.
Again - don't use eval or this method if you have another way to do that.
I wanted to be able to take a function name as a string, call it, AND pass an argument to the function. I couldn't get the selected answer for this question to do that, but this answer explained it exactly, and here is a short demo.
function test_function(argument) {
alert('This function ' + argument);
}
functionName = 'test_function';
window[functionName]('works!');
This also works with multiple arguments.
If settings.functionName is already a function, you could do this:
settings.functionName(t.parentNode.id);
Otherwise this should also work if settings.functionName is just the name of the function:
if (typeof window[settings.functionName] == "function") {
window[settings.functionName](t.parentNode.id);
}
This took me a while to figure out, as the conventional window['someFunctionName']() did not work for me at first. The names of my functions were being pulled as an AJAX response from a database. Also, for whatever reason, my functions were declared outside of the scope of the window, so in order to fix this I had to rewrite the functions I was calling from
function someFunctionName() {}
to
window.someFunctionName = function() {}
and from there I could call window['someFunctionName']() with ease. I hope this helps someone!
I prefer to use something like this:
window.callbackClass['newFunctionName'] = function(data) { console.log(data) };
...
window.callbackClass['newFunctionName'](data);
Based on Nicolas Gauthier answer:
var strng = 'someobj.someCallback';
var data = 'someData';
var func = window;
var funcSplit = strng.split('.');
for(i = 0;i < funcSplit.length;i++){
//We maybe can check typeof and break the bucle if typeof != function
func = func[funcSplit[i]];
}
func(data);
In javascript that uses the CommonJS spec, like node.js for instance you can do what I show below. Which is pretty handy for accessing a variable by a string even if its not defined on the window object. If there is a class named MyClass, defined within a CommonJS module named MyClass.js
// MyClass.js
var MyClass = function() {
// I do stuff in here. Probably return an object
return {
foo: "bar"
}
}
module.exports = MyClass;
You can then do this nice bit o witchcraft from another file called MyOtherFile.js
// MyOtherFile.js
var myString = "MyClass";
var MyClass = require('./' + myString);
var obj = new MyClass();
console.log(obj.foo); // returns "bar"
One more reason why CommonJS is such a pleasure.
eval("javascript code");
it is extensively used when dealing with JSON.