Execute functions whose names are in an array - javascript

I've seen How to execute a JavaScript function when I have its name as a string, Calling a JavaScript function named in a variable, Can I use the value of a variable to initiate a function?, but I can't figure out how to get this working with an array and a for loop.
What I've tried:
I have a few functions, let's say:
function one() {
alert('one');
}
function two() {
alert('two');
}
function three() {
alert('three');
}
and an array:
callThese = ['one', 'two']
and I want to call one and two.
This doesn't work:
for (i = 0; i < callThese.length; ++i) {
//console.log(callThese[i]); <--- (outputs one and two)
window[callThese[i]]();
}
The error I get is TypeError: object is not a function. The functions are definitely there, and they work by calling them manually (ie. one(), two(), etc...).
Sorry if this is a basic mistake, but how do I get this working?? I don't mind a jQuery solution if there is one.

You need to assign functions to your object. It's not recommended to create global functions (other scripts/frameworks can overwrite them).
var obj = {
one: function () {
alert('one');
},
two: function () {
alert('two');
},
three: function () {
alert('three');
}
},
callThese = ['one', 'two'];
for (var i = 0; i < callThese.length; ++i) {
obj[callThese[i]]();
}

You can create an object that contains the functions
var myFuncs = {
one: function () {
alert('one');
},
two: function () {
alert('two');
}
}
for (i = 0; i < callThese.length; ++i) {
myFuncs[callThese[i]]();
}

Related

Call a returned function from outside its function

I'm trying to call a function that's returned from a function. Here's what I mean:
myFunction.something; // (Wrong)
function myFunction() {
return {
something: function() {
...
}
};
}
When I try calling myFunction.something nothing happens. How can I call a returned function outside of its function?
JSFiddle
var index = 0;
var animID = requestAnimationFrame(myFunction.something);
function myFunction() {
return {
something: function() {
index++;
console.log(index);
if (index === 5) cancelAnimationFrame(animID);
else animID = requestAnimationFrame(myFunction.something);
}
};
}
I would first of all recommend using descriptive variable names; utils rather than myFunction, and incrementFrame rather than something, for example. I would second of all recommend reconsidering your approach to code organization and simply putting all of your helper functions directly in an object, then referencing that object:
var index = 0;
var animID = requestAnimationFrame(utils.incrementFrame);
var utils = {
incrementFrame: function() {
index++;
console.log(index);
if (index === 5) cancelAnimationFrame(animID);
else animID = requestAnimationFrame(utils.incrementFrame);
}
}
There are a few differences between these approaches, some of them frustratingly subtle. The primary reason I recommend using an object for organization rather than a function which returns an object is because you don't need to use a function for organization; you are unnecessarily complicating your code.
myfunction is not the object that you get from calling myfunction(), it's the function itself and does not have a .something method.
You could call it again (as in myfunction().something()), but a better approach would be to store a reference to the object you've already created:
function myFunction() {
var index = 0;
var o = {
something: function() {
index++;
console.log(index);
if (index < 5) requestAnimationFrame(o.something);
// btw you don't need to cancel anything once you reach 5, it's enough to continue not
}
};
return o;
}
myFunction().something();
Alternatively you might want to drop the function altogether, or use the module pattern (with an IIFE), as you seem to use it like a singleton anyway.
Try this:
myFunction().something()
myFunction() calls the myFunction function
them we use the dot notation on the returned value (which is an object) to find the something member of it
that member is a function too, so add another set of brackets () to call it
Call function after writing it
var index = 0;
function myFunction() {
return {
something: function() {
index++;
console.log(index);
if (index === 5) cancelAnimationFrame(animID);
else animID = requestAnimationFrame(myFunction().something);
}
};
}
var animID = requestAnimationFrame(myFunction().something);

Problems with scope

I am trying to assign a handler to every child element that I loop over. My problem is that the: target = child.items[i].id; will have the id of the last element that I loop over. So this part:
fn: function() {
isoNS.injectKey(target);
}
will always have the the id (target) of the last child. How can I do this?
I have tried put this in front, like this: isoNS.injectKey(this.target);
var arr=[];
for(var i = 0; i < obj.items.length; ++i) {
target = child.items[i].id;
arr.push({
key: sHolder.charAt(i),
fn: function() {
isoNS.injectKey(target);
},
});
}
So my main problem, is that each different value of: target = child.items[i].id; is overwritten with the latest element each time. I hope I am making myself understood.
In case you are wondering what obj and child is... I left them out to make the code shorter and more understandable. just know that they do have values in them, and are never null
You could do this
var arr = Array.prototype.map.call(obj.items, function(obj, i) {
return {
key: sHolder.charAt(i),
fn: function() {
isoNS.injectKey(child.items[i].id);
}
};
});
the Array map function provides the closure, and a nicer way to build up your arr
I use Array.prototype.map.call because there's no indication if obj.items is a TRUE array ... if it is, then it's a bit simpler
var arr = obj.items.map(function(obj, i) {
return {
key: sHolder.charAt(i),
fn: function() {
isoNS.injectKey(child.items[i].id);
}
};
});
The problem is your function is a closure and it has captured a reference to the target variable and this gets changed by your loop before the call back is invoked. A simple way to get around this is to wrap your function in another closure that captures the value of the target variable.
You can do this like so:
(function(capturedValue){
return function () {
// do something with the capturedValue
};
}(byRefObject));
The first function is part of an Immediately Invoked Function Expression (IIFE). It serves to capture the value of the byRefObject. You can read more about IIFE here.
Your code could look like this:
var arr=[];
for(var i = 0; i < obj.items.length; ++i) {
target = child.items[i].id;
arr.push({
key: sHolder.charAt(i),
fn: (function(target) {
return function() {
isoNS.injectKey(target);
};
})(target)
},
});
}
This has to do with closures:
var arr=[];
function getFunc(t){
return function() {
isoNS.injectKey(t);
}};
for(var i = 0; i < obj.items.length; ++i) {
target = child.items[i].id;
arr.push({
key: sHolder.charAt(i),
fn: getFunc(target),
});
}

JavaScript (NodeJS) equivalent for PHP's call_user_func_array()

Is there any equivalent function in JavaScript (NodeJS) similar to PHP's
call_user_func_array (http://php.net/manual/en/function.call-user-func-array.php). Which allows to call a function with array of parameters.
In my case, I have to call util.format with parameters that will be in an array.
Here is very simple example trying to show it.
var util = require("util");
function my_fundtion(items) {
var format_string = "";
for (var i=0; i < items.length; i++) {
format_string += " %s";
}
return util.format(format_string, /* here I want to pass items in items array */);
}
PHP has:
call_user_func_array('myfunc', array(1, 2, "foo", false));
While JS has:
myfunc.apply(null, [1, 2, "foo", false]);
The first null goes in the position of an object. You will make use of that if the function is intended to be a method. An example on using such invocation would be to slice array-like objects which are not arrays at all but seem like one (like the arguments object inside of a function):
Array.prototype.slice.apply(arguments, []);
Generally speaking, the syntax is:
(afunction).apply(obj|null, array of arguments)
You can try this:
function my_fundtion(items) {
var format_string = "";
for (var i=0; i < items.length; i++) {
format_string += " %s";
}
var new_items = items.slice();
new_items.unshift(format_string);
return util.format.apply(null, new_items);
}
IMHO that's the wrong approach for a function. Have you tried the following?
function my_fundtion(items) {
return items.join(" ");
}
Because call_user_func_array call function referenced by the function name which is in string. So, in JS we need to use eval.
Example:
const popup = (msg) => {
alert(msg);
}
const subject = {
popup(msg) {
alert(msg);
}
}
So,
eval("popup").apply(null, ['hi'])
eval("subject.popup").apply(null, ['hi'])
Correct me. If i wrong. ;)

Calling nested function using javascript

I have this code which calls a function test() on body onload
<body onLoad="test();">
The Test function has 2 more functions drawLayers() ,StopAll().
function test() {
function drawLayers() {
timers = [];
timers.push(setTimeout(drawMoon,800));
timers.push(setTimeout(drawCircle1,2300));
timers.push(setTimeout(drawCircle2,2700));
timers.push(setTimeout(drawCircle3,3100));
timers.push(setTimeout(drawCircle4,3500));
timers.push(setTimeout(drawCircle5,3900));
timers.push(setTimeout(drawtext2,4300));
timers.push(setTimeout(drawtext,4700));
timers.push(setTimeout(drawtext3,5100));
timers.push(setTimeout(drawtext4,5500));
timers.push(setTimeout(drawtext5,5900));
timers.push(setTimeout(drawtext6,6300));
timers.push(setTimeout(drawtext7,6700));
timers.push(setTimeout(drawtext8,7100));
timers.push(setTimeout(drawtext9,7500));
timers.push(setTimeout(drawtext10,7900));
}
function StopAll() {
alert('fsdfsdf');
for (var i = 0; i < timers.length; i++)
window.clearTimeout(timers[i]);
}
}
What i want to do is Call the StopAL() function on click of a button, the html code looks like below
<a href="javascript:void(0);" onClick="StopAll();">
Its throwing error, "StopAll is not defined"
How do i call the StopALL() function?
The scope of those nested functions is restricted to the test function only. You cannot invoke them from the outside. If you need to do that you could externalize it from the test function.
This is a 'closure' problem. The function StopAll is within the scope of the test function, and therefore is undefined in the global scope in which you are trying to call it.
Closures are a tricky subject to grasp initially. There's a good explanation here:
How do JavaScript closures work?
(by the way StopAll should really be called stopAll because capitalised functions are generally reserved for use with the new keyword.)
test = function (){
this.drawLayers = function() {
this.timers = [];
this.timers.push(setTimeout(drawMoon,800));
}
this.StopAll = function() {
alert('fsdfsdf');
var t = timers.length
for (var i = 0; i < t; i++)
window.clearTimeout(this.timers[i]);
}
}
var testObj = new test();
testObj.StopAll()
function test() {
function drawLayers() {
timers = [];
timers.push(setTimeout(drawMoon,800));
timers.push(setTimeout(drawCircle1,2300));
timers.push(setTimeout(drawCircle2,2700));
}
var StopAll=function() {
alert('fsdfsdf');
for (var i = 0; i < timers.length; i++)
window.clearTimeout(timers[i]);
}
return StopAll;
}
var obj= new test();
//to call StopAll function
obj();
(function test($) {
function drawLayers() {
}
//expose this to outside world ,public function
$.StopAll = function() {
alert('fsdfsdf');
}
})(window);
StopAll();
You'd better not use html attributes to bind event handler, you can do the same with the following code:
window.onload = function(){
document.getElementById("myLink").onclick = function(){
StopAll();
}
}
// Your functions
This way you'll ensure your dom is loaded and ready to call event handlers.
You can move the function StopAll() outside the test function and call it as specified. If suppose you need to access that function even in the test(), you can do like this
function test() {
.....
drawLayers();
StopAll() ;
}
function StopAll() {
alert('fsdfsdf');
for (var i = 0; i < timers.length; i++)
window.clearTimeout(timers[i]);
}
Declaration of function can be given outside and called any where you want

Javascript Array of Functions

var array_of_functions = [
first_function('a string'),
second_function('a string'),
third_function('a string'),
forth_function('a string')
]
array_of_functions[0];
That does not work as intended because each function in the array is executed when the array is created.
What is the proper way of executing any function in the array by doing:
array_of_functions[0]; // or, array_of_functions[1] etc.
Thanks!
var array_of_functions = [
first_function,
second_function,
third_function,
forth_function
]
and then when you want to execute a given function in the array:
array_of_functions[0]('a string');
I think this is what the original poster meant to accomplish:
var array_of_functions = [
function() { first_function('a string') },
function() { second_function('a string') },
function() { third_function('a string') },
function() { fourth_function('a string') }
]
for (i = 0; i < array_of_functions.length; i++) {
array_of_functions[i]();
}
Hopefully this will help others (like me 20 minutes ago :-) looking for any hint about how to call JS functions in an array.
Without more detail of what you are trying to accomplish, we are kinda guessing. But you might be able to get away with using object notation to do something like this...
var myFuncs = {
firstFunc: function(string) {
// do something
},
secondFunc: function(string) {
// do something
},
thirdFunc: function(string) {
// do something
}
}
and to call one of them...
myFuncs.firstFunc('a string')
I would complement this thread by posting an easier way to execute various functions within an Array using the shift() Javascript method originally described here
var a = function(){ console.log("this is function: a") }
var b = function(){ console.log("this is function: b") }
var c = function(){ console.log("this is function: c") }
var foo = [a,b,c];
while (foo.length){
foo.shift().call();
}
Or just:
var myFuncs = {
firstFun: function(string) {
// do something
},
secondFunc: function(string) {
// do something
},
thirdFunc: function(string) {
// do something
}
}
It's basically the same as Darin Dimitrov's but it shows how you could use it do dynamically create and store functions and arguments.
I hope it's useful for you :)
var argsContainer = ['hello', 'you', 'there'];
var functionsContainer = [];
for (var i = 0; i < argsContainer.length; i++) {
var currentArg = argsContainer[i];
functionsContainer.push(function(currentArg){
console.log(currentArg);
});
};
for (var i = 0; i < functionsContainer.length; i++) {
functionsContainer[i](argsContainer[i]);
}
up above we saw some with iteration. Let's do the same thing using forEach:
var funcs = [function () {
console.log(1)
},
function () {
console.log(2)
}
];
funcs.forEach(function (func) {
func(); // outputs 1, then 2
});
//for (i = 0; i < funcs.length; i++) funcs[i]();
Ah man there are so many weird answers...
const execute = (fn) => fn()
const arrayOfFunctions = [fn1, fn2, fn3]
const results = arrayOfFunctions.map(execute)
or if you want to sequentially feed each functions result to the next:
compose(fn3, fn2, fn1)
compose is not supported by default, but there are libraries like ramda, lodash, or even redux which provide this tool
This is correct
var array_of_functions = {
"all": function(flag) {
console.log(1+flag);
},
"cic": function(flag) {
console.log(13+flag);
}
};
array_of_functions.all(27);
array_of_functions.cic(7);
If you're doing something like trying to dynamically pass callbacks you could pass a single object as an argument. This gives you much greater control over which functions you want to you execute with any parameter.
function func_one(arg) {
console.log(arg)
};
function func_two(arg) {
console.log(arg+' make this different')
};
var obj = {
callbacks: [func_one, func_two],
params: ["something", "something else"];
};
function doSomething(obj) {
var n = obj.counter
for (n; n < (obj.callbacks.length - obj.len); n++) {
obj.callbacks[n](obj.params[n]);
}
};
obj.counter = 0;
obj.len = 0;
doSomething(obj);
//something
//something else make this different
obj.counter = 1;
obj.len = 0;
doSomething(obj);
//something else make this different
Execution of many functions through an ES6 callback 🤗
const f = (funs) => {
funs().forEach((fun) => fun)
}
f(() => [
console.log(1),
console.log(2),
console.log(3)
])
Using ES6 syntax, if you need a "pipeline" like process where you pass the same object through a series of functions (in my case, a HTML abstract syntax tree), you can use for...of to call each pipe function in a given array:
const setMainElement = require("./set-main-element.js")
const cacheImages = require("./cache-images.js")
const removeElements = require("./remove-elements.js")
let htmlAst = {}
const pipeline = [
setMainElement,
cacheImages,
removeElements,
(htmlAst) => {
// Using a dynamic closure.
},
]
for (const pipe of pipeline) {
pipe(htmlAst)
}
A short way to run 'em all:
[first_function, ..., nth_function].forEach (function(f) {
f('a string');
});
the probleme of these array of function are not in the "array form" but in the way these functions are called... then...
try this.. with a simple eval()...
array_of_function = ["fx1()","fx2()","fx3()",.."fxN()"]
var zzz=[];
for (var i=0; i<array_of_function.length; i++)
{ var zzz += eval( array_of_function[i] ); }
it work's here, where nothing upper was doing the job at home...
hopes it will help
Using Function.prototype.bind()
var array_of_functions = [
first_function.bind(null,'a string'),
second_function.bind(null,'a string'),
third_function.bind(null,'a string'),
forth_function.bind(null,'a string')
]
I have many problems trying to solve this one... tried the obvious, but did not work. It just append an empty function somehow.
array_of_functions.push(function() { first_function('a string') });
I solved it by using an array of strings, and later with eval:
array_of_functions.push("first_function('a string')");
for (var Func of array_of_functions) {
eval(Func);
}
maybe something like this would do the trick:
[f1,f2,f3].map((f) => f('a string'))
Maybe it can helps to someone.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.manager = {
curHandler: 0,
handlers : []
};
manager.run = function (n) {
this.handlers[this.curHandler](n);
};
manager.changeHandler = function (n) {
if (n >= this.handlers.length || n < 0) {
throw new Error('n must be from 0 to ' + (this.handlers.length - 1), n);
}
this.curHandler = n;
};
var a = function (n) {
console.log("Handler a. Argument value is " + n);
};
var b = function (n) {
console.log("Handler b. Argument value is " + n);
};
var c = function foo(n) {
for (var i=0; i<n; i++) {
console.log(i);
}
};
manager.handlers.push(a);
manager.handlers.push(b);
manager.handlers.push(c);
</script>
</head>
<body>
<input type="button" onclick="window.manager.run(2)" value="Run handler with parameter 2">
<input type="button" onclick="window.manager.run(4)" value="Run handler with parameter 4">
<p>
<div>
<select name="featured" size="1" id="item1">
<option value="0">First handler</option>
<option value="1">Second handler</option>
<option value="2">Third handler</option>
</select>
<input type="button" onclick="manager.changeHandler(document.getElementById('item1').value);" value="Change handler">
</div>
</p>
</body>
</html>
This answered helped me but I got stuck trying to call each function in my array a few times. So for rookies, here is how to make an array of functions and call one or all of them, a couple different ways.
First we make the array.
let functionsArray = [functionOne, functionTwo, functionThree];
We can call a specific function in the array by using its index in the array (remember 0 is the first function in the array).
functionsArray[0]();
We have to put the parenthesis after because otherwise we are just referencing the function, not calling it.
If you wanted to call all the functions we could use a couple different ways.
For loop
for (let index = 0; index < functionsArray.length; index++) {
functionsArray[index]();
}
Don't forget the parenthesis to actually call the function.
ForEach
ForEach is nice because we don't have to worry about the index, we just get handed each element in the array which we can use. We use it like this (non arrow function example below):
functionsArray.forEach(element => {
element();
});
In a ForEach you can rename element in the above to be whatever you want. Renaming it, and not using arrow functions could look like this:
functionsArray.forEach(
function(funFunctionPassedIn) {
funFunctionPassedIn();
}
);
What about Map?
We shouldn't use Map in this case, since map builds a new array, and using map when we aren't using the returned array is an anti-pattern (bad practice).
We shouldn't be using map if we are not using the array it returns, and/or
we are not returning a value from the callback. Source
I know I am late to the party but here is my opinion
let new_array = [
(data)=>{console.log(data)},
(data)=>{console.log(data+1)},
(data)=>{console.log(data+2)}
]
new_array[0]
you got some top answers above. This is just another version of that.
var dictFun = {
FunOne: function(string) {
console.log("first function");
},
FuncTwo: function(string) {
console.log("second function");
},
FuncThree: function(string) {
console.log("third function");
}
}
/* PlanetGreeter */
class PlanetGreeter {
hello : { () : void; } [] = [];
planet_1 : string = "World";
planet_2 : string = "Mars";
planet_3 : string = "Venus";
planet_4 : string = "Uranus";
planet_5 : string = "Pluto";
constructor() {
this.hello.push( () => { this.greet(this.planet_1); } );
this.hello.push( () => { this.greet(this.planet_2); } );
this.hello.push( () => { this.greet(this.planet_3); } );
this.hello.push( () => { this.greet(this.planet_4); } );
this.hello.push( () => { this.greet(this.planet_5); } );
}
greet(a: string) : void { alert("Hello " + a); }
greetRandomPlanet() : void {
this.hello [ Math.floor( 5 * Math.random() ) ] ();
}
}
new PlanetGreeter().greetRandomPlanet();

Categories

Resources