Call a function from a string in JS - javascript

I have an array of strings that I wish to use as callbacks, but the below code is not working.
When running the function, I'm getting the error TypeError: fn is not a function logged when callback_array contains only update_front_page_images.
callback_array currently only contains 1 element (update_front_page_images), which is the name of a function I wish to run.
Can someone please let me know what I am doing wrong?
function run_reset_callbacks(callback_array){
for(var key in callback_array){
try {
fn = window[callback_array[key]];
fn();
}
catch(err) {
console.log('Function \''+callback_array[key]+'\' does not exist. '+err);
}
}
}

Make sure you're defining your functions in a way that you can call them as window[] if you want to use this model. You need to define your functions as variables on the window object. A standard function definition will fail.
http://jsfiddle.net/HpXYM/2/
//Works
window.hello = function () {
alert("hello");
};
//Works
test = function () {
alert("test");
};
//Fails
function fail() {
alert("fail")
};
This should solve the problem if you are set on this method but I would recommend you follow Matt Ball's advice.

Change your Scope! I think you are not able to access window:
JS Fiddle Link
var outputDiv = document.getElementById('output');
// Wrong
var cbArray = ['update_front_page_images', 'dummyFunction']; // Array created from PHP
function update_front_page_images() {
outputDiv.innerHTML = outputDiv.innerHTML+ '<br/>' + 'Called me? I am "update_front_page_images" !!';
}
function dummyFunction() {
outputDiv.innerHTML = outputDiv.innerHTML+ '<br/>' + 'Called me? I am "" !!';
}
// -- Wrong
// Right
var cbArray = {
'update_front_page_images': function() {
outputDiv.innerHTML = outputDiv.innerHTML+ '<br/>' + 'Called me? I am "update_front_page_images" !!';
},
'dummyFunction': function() {
outputDiv.innerHTML = outputDiv.innerHTML+ '<br/>' + 'Called me? I am "dummyFunction" !!';
}
}
// -- Right
// your Code
function run_reset_callbacks(callback_array){
for(var key in callback_array){
try {
fn = window[callback_array[key]]; // Wrong
fn = callback_array[key]; // Right
fn();
}
catch(err) {
outputDiv.innerHTML = 'Function \''+callback_array[key]+'\' does not exist. '+err;
}
}
}
run_reset_callbacks(cbArray);

Arrays should be enumerated with an indexed loop:
for (var i = 0; i < callback_array.length; i++) { ... }
If callback_array is really a literal object, the approach above is fine, but it would be safer to check for hasOwnProperty before evaluating the property.
if(callback_array.hasOwnProperty(key)) { ... } // use it
Otherwise, make sure that update_front_page_images is within the global scope and ready for evaluation at the time this function is called.

Related

Avoiding a global variable

The purpose of the example code below is to be able to restrict a function from printing something via console.log (a loop in this case) if the function is executed twice.
However, the function uses the global variable "condition" and I want to find a way to avoid this. I've been playing around with workarounds, but to no avail. Also, I have checked sources online, but relate to other more complex examples which are beyond my level. This is a simpler example, but haven't been able to crack this.
Grateful for some guidance. Thanks.
let condition = false;
const testFunc = function (value) {
for (let i = 0; i < 10; i++) {
if (!condition) {
console.log(value + i);
}
}
condition = true;
};
testFunc(5);
testFunc(5);
The usual answer is to create yet another scope to hold the state:
function once(fn) {
let called = false
return function(...args) {
if (!called) {
fn(...args)
called = true
}
}
}
const test = once(function() {
console.log('hello')
})
test() // hello
test() // nothing
Thanks for your feedback - I considered the use of using closure by way of returning a function within another.
Would this be a viable option in order to avoid a global variable? Note that "func" needs to be declared globally -
const testFuncEncaps = function (value) {
let trueOrFalse = false;
return function () {
for (let i = 0; i < 10; i++) {
if (!trueOrFalse) {
console.log(value + i);
}
}
trueOrFalse = true;
};
};
let func = testFuncEncaps(5);
func();
func();

JS Function returning function for later use - arguments undefined

I am trying to create a function that can then return many functions based on an input. Here is an example of the problem I am facing.
var giveFunction = function(text) {
return function(text) {
console.log(text)
}
}
var test = giveFunction('this is a test');
test()
Running test() at the end prints undefined instead of 'this is a test.' Is there any way around this problem?
The inner function should not contain any parameter,
var giveFunction = function(text) {
return function() {
console.log(text)
}
}
Let it create a closure. If it has a parameter then that would be read during execution and undefined would be printed as you are not calling that function with any arguments.
If you want your code to be working then you have to use bind for that,
var giveFunction = function(text) {
return function(text) {
console.log(text)
}.bind(null, text)
}
var test = giveFunction('this is a test');
test(); //'this is a test'
Lets go one step further and ask why?
var outerFunction = function(outerParameter) {
return innerFunction function(innerParameter) {
// in here we have access to anything in this function and the outer function
// all the way to out the the global scope
// therefore, we dont need to pass innerParameter in again as a parameter! ( in your case we 'next')
}
/// now over here, outside of innerFunction, we do NOT have access to innerParameter!
}
So applying the above principles to your code we have:
var giveFunction = function(text) {
return function() {
console.log(text)
}
}
var test = giveFunction('this is a test');
test()
which now works!
Finally, checkout the most upvoted post under the javascript tag:
How do JavaScript closures work?

How can I get my anonymous JavaScript function to execute withing the calling scope?

I'm trying to make a generic error message function that I can use within any JavaScript function. This function would test for certain validity and stop the calling function dead-cold if it fails.
For example:
var fun = function() {
var a = {};
a.blah = 'Hello';
checkIfExistErrorIfNot(a); // fine, continue on...
checkIfExistErrorIfNot(a.blah); // fine, continue on...
checkIfExistErrorIfNot(a.notDefined); // error. stop calling method ("fun") from continuing
console.log('Yeah! You made it here!');
}
This was my first stab at it:
var checkIfExistErrorIfNot(obj) {
var msg = 'Object does not exist.';
if(!obj) {
return (function() {
console.log(msg);
return false;
})();
}
return true;
}
The returning anonymous function executes just fine. But the calling function still continues. I'm guessing it's because the anon function does not execute in the scope of the calling function.
Thanks.
EDIT
I may not have made my intentions clear. Here is what I normally do in my methods:
saveData: function() {
var store = this.getStore();
var someObj = this.getOtherObject();
if(!store || !someObj) {
showError('There was an error');
return false; // now, 'saveData' will not continue
}
// continue on with save....
}
This is what I'd like to do:
saveData: function() {
var store = this.getStore();
var someObj = this.getOtherObject();
checkIfExistErrorIfNot(store);
checkIfExistErrorIfNot(someObj);
// continue on with save....
}
Now, what would be even cooler would be:
...
checkIfExistErrorIfNot( [store, someObj] );
...
And iterate through the array...cancelling on the first item that isn't defined. But I could add the array piece if I can find out how to get the first part to work.
Thanks
You can use exceptions for that:
var checkIfExistErrorIfNot = function (obj) {
var msg = 'Object does not exist.';
if(!obj) {
throw new Error(msg);
}
}
var fun = function() {
var a = {};
a.blah = 'Hello';
try {
console.log('a:');
checkIfExistErrorIfNot(a); // fine, continue on...
console.log('a.blah:');
checkIfExistErrorIfNot(a.blah); // fine, continue on...
console.log('a.notDefined:');
checkIfExistErrorIfNot(a.notDefined); // error. stop calling method ("fun") from continuing
} catch (e) {
return false;
}
console.log('Yeah! You made it here!');
return true;
}
console.log(fun());

Function naming and launching

Why this is working:
JS
$(gallery_1 + " .gallery_comandi #next").click(function avanti_gallery() {
contatore ++;
if (contatore > tot_immagini) {
contatore = 1;
cambia_immagine ();
}
else { cambia_immagine ();
};
});
And this isn't? This second cose executes the function. Why? Shouldn't it be lauched by a command like avanti_gallery()?
JS
function avanti_gallery() {
contatore ++;
if (contatore > tot_immagini) {
contatore = 1;
cambia_immagine ();
}
else { cambia_immagine ();
};
};
$(gallery_1 + " .gallery_comandi #next").click(avanti_gallery());
You're passing the result, not the reference to the function.
Try this
$(gallery_1 + " .gallery_comandi #next").click(avanti_gallery);
With
$(gallery_1 + " .gallery_comandi #next").click(avanti_gallery());
...you're calling the function and passing the return value into click, exactly the same as foo(bar()) calls bar and passes the return value into foo.
Ditch the ():
$(gallery_1 + " .gallery_comandi #next").click(avanti_gallery);
// Here -----------------------------------------------------^
The reason your first one works is that you're only defining, not calling, the function. The () after the name in that expression are just part of the definition (specifically, part of the named function expression), whereas the () in the second example are actually calling the function.
It may be easier to tell the difference if we remove click from the picture:
Your first one:
var f = function avanti_gallery() {
contatore ++;
if (contatore > tot_immagini) {
contatore = 1;
cambia_immagine ();
}
else { cambia_immagine ();
};
};
(I need the var f = at the beginning or the named function expression changes into a function declaration, which although it looks the same is quite different, and it shows visually that we're using the resulting function reference)
Your second one:
var f = avanti_gallery();

Function in JavaScript that can be called only once

I need to create a function which can be executed only once, in each time after the first it won't be executed. I know from C++ and Java about static variables that can do the work but I would like to know if there is a more elegant way to do this?
If by "won't be executed" you mean "will do nothing when called more than once", you can create a closure:
var something = (function() {
var executed = false;
return function() {
if (!executed) {
executed = true;
// do something
}
};
})();
something(); // "do something" happens
something(); // nothing happens
In answer to a comment by #Vladloffe (now deleted): With a global variable, other code could reset the value of the "executed" flag (whatever name you pick for it). With a closure, other code has no way to do that, either accidentally or deliberately.
As other answers here point out, several libraries (such as Underscore and Ramda) have a little utility function (typically named once()[*]) that accepts a function as an argument and returns another function that calls the supplied function exactly once, regardless of how many times the returned function is called. The returned function also caches the value first returned by the supplied function and returns that on subsequent calls.
However, if you aren't using such a third-party library, but still want a utility function (rather than the nonce solution I offered above), it's easy enough to implement. The nicest version I've seen is this one posted by David Walsh:
function once(fn, context) {
var result;
return function() {
if (fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
I would be inclined to change fn = null; to fn = context = null;. There's no reason for the closure to maintain a reference to context once fn has been called.
Usage:
function something() { /* do something */ }
var one_something = once(something);
one_something(); // "do something" happens
one_something(); // nothing happens
[*] Be aware, though, that other libraries, such as this Drupal extension to jQuery, may have a function named once() that does something quite different.
Replace it with a reusable NOOP (no operation) function.
// this function does nothing
function noop() {};
function foo() {
foo = noop; // swap the functions
// do your thing
}
function bar() {
bar = noop; // swap the functions
// do your thing
}
Point to an empty function once it has been called:
function myFunc(){
myFunc = function(){}; // kill it as soon as it was called
console.log('call once and never again!'); // your stuff here
};
<button onClick=myFunc()>Call myFunc()</button>
Or, like so:
var myFunc = function func(){
if( myFunc.fired ) return;
myFunc.fired = true;
console.log('called once and never again!'); // your stuff here
};
// even if referenced & "renamed"
((refToMyfunc)=>{
setInterval(refToMyfunc, 1000);
})(myFunc)
UnderscoreJs has a function that does that, underscorejs.org/#once
// Returns a function that will be executed at most one time, no matter how
// often you call it. Useful for lazy initialization.
_.once = function(func) {
var ran = false, memo;
return function() {
if (ran) return memo;
ran = true;
memo = func.apply(this, arguments);
func = null;
return memo;
};
};
Talking about static variables, this is a little bit like closure variant:
var once = function() {
if(once.done) return;
console.log('Doing this once!');
once.done = true;
};
once(); // Logs "Doing this once!"
once(); // Logs nothing
You could then reset a function if you wish:
once.done = false;
once(); // Logs "Doing this once!" again
You could simply have the function "remove itself"
​function Once(){
console.log("run");
Once = undefined;
}
Once(); // run
Once(); // Uncaught TypeError: undefined is not a function
But this may not be the best answer if you don't want to be swallowing errors.
You could also do this:
function Once(){
console.log("run");
Once = function(){};
}
Once(); // run
Once(); // nothing happens
I need it to work like smart pointer, if there no elements from type A it can be executed, if there is one or more A elements the function can't be executed.
function Conditional(){
if (!<no elements from type A>) return;
// do stuff
}
var quit = false;
function something() {
if(quit) {
return;
}
quit = true;
... other code....
}
simple decorator that easy to write when you need
function one(func) {
return function () {
func && func.apply(this, arguments);
func = null;
}
}
using:
var initializer= one( _ =>{
console.log('initializing')
})
initializer() // 'initializing'
initializer() // nop
initializer() // nop
try this
var fun = (function() {
var called = false;
return function() {
if (!called) {
console.log("I called");
called = true;
}
}
})()
From some dude named Crockford... :)
function once(func) {
return function () {
var f = func;
func = null;
return f.apply(
this,
arguments
);
};
}
Reusable invalidate function which works with setInterval:
var myFunc = function (){
if (invalidate(arguments)) return;
console.log('called once and never again!'); // your stuff here
};
const invalidate = function(a) {
var fired = a.callee.fired;
a.callee.fired = true;
return fired;
}
setInterval(myFunc, 1000);
Try it on JSBin: https://jsbin.com/vicipar/edit?js,console
Variation of answer from Bunyk
Here is an example JSFiddle - http://jsfiddle.net/6yL6t/
And the code:
function hashCode(str) {
var hash = 0, i, chr, len;
if (str.length == 0) return hash;
for (i = 0, len = str.length; i < len; i++) {
chr = str.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
}
var onceHashes = {};
function once(func) {
var unique = hashCode(func.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1]);
if (!onceHashes[unique]) {
onceHashes[unique] = true;
func();
}
}
You could do:
for (var i=0; i<10; i++) {
once(function() {
alert(i);
});
}
And it will run only once :)
Initial setup:
var once = function( once_fn ) {
var ret, is_called;
// return new function which is our control function
// to make sure once_fn is only called once:
return function(arg1, arg2, arg3) {
if ( is_called ) return ret;
is_called = true;
// return the result from once_fn and store to so we can return it multiply times:
// you might wanna look at Function.prototype.apply:
ret = once_fn(arg1, arg2, arg3);
return ret;
};
}
If your using Node.js or writing JavaScript with browserify, consider the "once" npm module:
var once = require('once')
function load (file, cb) {
cb = once(cb)
loader.load('file')
loader.once('load', cb)
loader.once('error', cb)
}
If you want to be able to reuse the function in the future then this works well based on ed Hopp's code above (I realize that the original question didn't call for this extra feature!):
var something = (function() {
var executed = false;
return function(value) {
// if an argument is not present then
if(arguments.length == 0) {
if (!executed) {
executed = true;
//Do stuff here only once unless reset
console.log("Hello World!");
}
else return;
} else {
// otherwise allow the function to fire again
executed = value;
return;
}
}
})();
something();//Hello World!
something();
something();
console.log("Reset"); //Reset
something(false);
something();//Hello World!
something();
something();
The output look like:
Hello World!
Reset
Hello World!
A simple example for turning on light only once.
function turnOnLightOnce() {
let lightOn = false;
return function () {
if (!lightOn) {
console.log("Light is not on...Turning it on for first and last time");
lightOn = true;
}
};
}
const lightOn = turnOnLightOnce();
lightOn() // Light is not on...Turning it on for first and last time
lightOn()
lightOn()
lightOn()
lightOn()
https://codesandbox.io/s/javascript-forked-ojo0i?file=/index.js
This happens due to closure in JavaScript.
function once (fn1) {
var ran = false
var memo = null
var fn = function(...args) {
if(ran) {return memo}
ran = true
memo = fn1.apply(null, args)
return memo
}
return fn
}
I'm using typescript with node and it was #I Hate Lazy's answer that inspired me. I just assigned my function to a noop function.
let printName = (name: string) => {
console.log(name)
printName = () => {}
}
printName('Sophia') // Sophia
printName('Nico') // Nothing Happens
https://jsbin.com/yuzicek/edit?js,console
FOR EVENT HANDLER
If the function is a callback for an event listener, there is already a built-in option in the addEventListner method for just executing the callback once.
It can accept 3 parameters
Type
callback
options
options is an object that has a property called once
ex:
const button = document.getElementById('button');
const callbackFunc = () => {
alert('run')
}
button.addEventListener('click', callbackFunc, { once: true })
<button id="button">Click Once</button>
Trying to use underscore "once" function:
var initialize = _.once(createApplication);
initialize();
initialize();
// Application is only created once.
http://underscorejs.org/#once
var init = function() {
console.log("logges only once");
init = false;
};
if(init) { init(); }
/* next time executing init() will cause error because now init is
-equal to false, thus typing init will return false; */
if (!window.doesThisOnce){
function myFunction() {
// do something
window.doesThisOnce = true;
};
};
If you're using Ramda, you can use the function "once".
A quote from the documentation:
once Function
(a… → b) → (a… → b)
PARAMETERS
Added in v0.1.0
Accepts a function fn and returns a function that guards invocation of fn such that fn can only ever be called once, no matter how many times the returned function is invoked. The first value calculated is returned in subsequent invocations.
var addOneOnce = R.once(x => x + 1);
addOneOnce(10); //=> 11
addOneOnce(addOneOnce(50)); //=> 11
keep it as simple as possible
function sree(){
console.log('hey');
window.sree = _=>{};
}
You can see the result
JQuery allows to call the function only once using the method one():
let func = function() {
console.log('Calling just once!');
}
let elem = $('#example');
elem.one('click', func);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<p>Function that can be called only once</p>
<button id="example" >JQuery one()</button>
</div>
Implementation using JQuery method on():
let func = function(e) {
console.log('Calling just once!');
$(e.target).off(e.type, func)
}
let elem = $('#example');
elem.on('click', func);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<p>Function that can be called only once</p>
<button id="example" >JQuery on()</button>
</div>
Implementation using native JS:
let func = function(e) {
console.log('Calling just once!');
e.target.removeEventListener(e.type, func);
}
let elem = document.getElementById('example');
elem.addEventListener('click', func);
<div>
<p>Functions that can be called only once</p>
<button id="example" >ECMAScript addEventListener</button>
</div>
Tossing my hat in the ring for fun, added advantage of memoizing
const callOnce = (fn, i=0, memo) => () => i++ ? memo : (memo = fn());
// usage
const myExpensiveFunction = () => { return console.log('joe'),5; }
const memoed = callOnce(myExpensiveFunction);
memoed(); //logs "joe", returns 5
memoed(); // returns 5
memoed(); // returns 5
...
You can use IIFE. IIFE means Immediately Invoked Function Expression and the result is to call a function only once by the time is created.
Your code will be like this:
(function () {
//The code you want to execute only one time etc...
console.log("Hello world");
})()
Additionally, this way the data in the function remains encapsulated.
Of course and you can return values from the function and stored them into a new variable, by doing:
const/let value = (function () {
//The code you want to execute only one time etc...
const x = 10;
return x;
})()
function x()
{
let a=0;
return function check()
{
if(!a++)
{
console.log("This Function will execute Once.")
return;
}
console.log("You Can't Execute it For the Second Time.")
return;
}
}
z=x()
z() //Op - This Function will execute once
z() //OP - You can't Execute it for the second time.
I find it useful to just have a simple function that just returns true once, so you can keep the side effects higher up.
let once = () => !! (once = () => false);
once() // true
once() // false
Use like this:
if (once()) {
sideEffect()
}
This exploits the fact that you can coerce an assignment expression to return true while changing the same function into a function that returns false.
If you must have it execute a function, it can be adapted using a ternary:
let once = (x) => !! (once = () => false) ? x() : false;
Now it accepts a single function as an argument. Fun fact, the second false is never reached.
// This is how function in JavaScript can be called only once
let started = false;
if (!started) {
start() { // "do something" }
}
started = true;
}

Categories