I have a js file with many functions
function one(){
//do stuff
}
function two(){
//do stuff
}
function execute_top_one(){
//do stuff
}
function execute_top_two(){
//do stuff
}
and I need to create a function that executes, for example, all functions that start with (or contain) "execute_top" in the function name, instead of having to call all the functions manually like this
execute_top_one();
execute_top_two();
Any suggestion?
I would suggest that you do it in a little other way:
const functionStore = {
one: function() {
console.log('one')
},
two: function() {
console.log('two')
},
execute_top_one: function() {
console.log('execute_top_one')
},
execute_top_two: function() {
console.log('execute_top_two')
},
}
const execute_these = "execute_top"
const executeFunctions = (functionStore, filterString) => {
Object.entries(functionStore).forEach(([fnName, fn]) => {
if (fnName.indexOf(filterString) !== -1) {
fn()
}
})
}
executeFunctions(functionStore, execute_these)
The difference is that you gather your functions into one object (I called it functionStore, and then create the filtering string & function. As you see from the snippet, filtering an object's keys and values (called fnName & fn in my snippet) is quite easy - and inside the filtering you can call the functions stored.
Related
I have many functions example like this
function update() {
if (isAdminUser()) {
return false;
}
...
}
function get() {
if (isAdminUser()) {
return false;
}
...
}
...
is there any possible way to have the conditional statement
if (isAdminUser()) {
return false;
})
written once and run by itself at the beginning of each function. I'm using javascript
You could use a higher order function to encapsulate the logic needed to run before a specific function is run. Higher order functions take functions as parameters, therefore a possible solution to your problem could look like this:
function withIsAdminUser(callback) {
return function() {
if (isAdminUser()) {
return false;
}
return callback();
}
}
function getRaw() {
// Do something here, this whole function could also be inlined
}
const get = withIsAdminUser(getRaw);
If you use TypeScript try decorators.
Docs: https://www.typescriptlang.org/docs/handbook/decorators.html#decorators
maybe you can define a function that can accept another function as an argument and returns false if that function (i.e isAdminUser in your code snippet) returns true
const checkUser = func => func() && false
then the function can be used like:
function update() {
if (checkUser(isAdminUser)) {
// update() logic will only run if user is not admin
}
}
function get() {
if (checkUser(isAdminUser)) {
// get() logic will only run if user is not admin
}
}
Scenario: I am developing a chrome extension and I have a bunch of listeners I need to add in the foreground.
What I would like to do: create an object named 'listeners' containing only functions (functions that will run addListeners), and a function called 'init' that would iterate my 'listeners' object and dynamically execute every function.
Why: I would like to add new listeners to the object without worrying about having to call them directly one by one in my init function. I know it would not be too much of a hassle doing so but it would be interesting if I could make the thing more dynamic.
Is this possible?
Something like:
const listeners = {
func1: function (){...},
func2: function (){...},
func3: function (){...}
}
function init(){
for (let func in listeners){
//somehow execute func
//func() appearently does not work
//()=>func appearently does not work
}
}
init();
The for...in loop iterates the keys of the object, so the func variable is a string, and not a function. To run the function use listeners[func]();.
You can use Object.values() to get an of functions, and then iterate it with for...of:
const listeners = {
func1(){ console.log(1); },
func2(){ console.log(2); },
func3(){ console.log(3); }
}
function init(){
for (const func of Object.values(listeners)){
func()
}
}
init();
Or do the same with Array.forEach():
const listeners = {
func1(){ console.log(1); },
func2(){ console.log(2); },
func3(){ console.log(3); }
}
const init = () => Object.values(listeners).forEach(func => func())
init();
Try this:
const listeners = {
func1: function () {
console.log(1);
},
func2: function () {
console.log(2);
},
func3: function () {
console.log(3);
}
}
function init() {
for (let func in listeners) {
listeners[func]();
}
}
init();
On top of the other answers. I think Array structure is more appropriate in your case.
const listeners = [
function () {
console.log(1);
},
function () {
console.log(2);
},
function () {
console.log(3);
},
];
function init() {
listeners.forEach(func => func());
}
init();
you will just need to do it like that listeners[func]() in the loop , in for in loop, keys are the one iterated, so you call items like that obj/array[key] func in your case
and while you have functions you need to add ().
check inspect in this fiddler link
I see different topics about the toggle function in jquery, but what is now really the best way to toggle between functions?
Is there maybe some way to do it so i don't have to garbage collect all my toggle scripts?
Some of the examples are:
var first=true;
function toggle() {
if(first) {
first= false;
// function 1
}
else {
first=true;
// function 2
}
}
And
var first=true;
function toggle() {
if(first) {
// function 1
}
else {
// function 2
}
first = !first;
}
And
var first=true;
function toggle() {
(first) ? function_1() : function_2();
first != first;
}
function function_1(){}
function function_2(){}
return an new function
var foo = (function(){
var condition
, body
body = function () {
if(condition){
//thing here
} else {
//other things here
}
}
return body
}())`
Best really depends on the criteria your application demands. This might not be the best way to this is certainly a cute way to do it:
function toggler(a, b) {
var current;
return function() {
current = current === a ? b : a;
current();
}
}
var myToggle = toggler(function_1, function_2);
myToggle(); // executes function_1
myToggle(); // executes function_2
myToggle(); // executes function_1
It's an old question but i'd like to contribute too..
Sometimes in large project i have allot of toggle scripts and use global variables to determine if it is toggled or not. So those variables needs to garbage collect for organizing variables, like if i maybe use the same variable name somehow or things like that
You could try something like this..: (using your first example)
function toggle() {
var self = arguments.callee;
if (self.first === true) {
self.first = false;
// function 1
}
else {
self.first = true;
// function 2
}
}
Without a global variable. I just added the property first to the function scope.
This way can be used the same property name for other toggle functions too.
Warning: arguments.callee is forbidden in 'strict mode'
Otherwise you may directly assign the first property to the function using directly the function name
function toggle() {
if (toggle.first === true) {
toggle.first = false;
// function 1
}
else {
toggle.first = true;
// function 2
}
}
I have a member function in the object which gets the array of callback functions and the name of the event for which this function is set:
...
setHandlesByList: function (list) {
for (var i in list) {
var self = this;
$(document).on(list[i].name, function (e) {
list[i].callBack.call(self,e)
});
};
},
...
Somewhere in the child objects I have a call to this function of the parent object:
...
initClass: function () {
this.setHandlesByList([
{ name: 'configChecked', callBack: onConfigChecked },
{ name: 'configExpired', callBack: onConfigExpired },
]);
},
onConfigChecked: function() {
// some code
},
onConfigExpired: function() {
// some code
},
....
but something goes wrong - for all events the handler is the last set callback function...
Try the following:
setHandlesByList: function (list) {
for ( var i = 0; i < list.length; i++ ) {
addCallback(list[i].name, list[i].callback);
}
function addCallback(on, name, callback) {
$(document).on(name, function(e) { callback.call(on, e); });
}
},
There is a problem with your scoping, because the value of i eventually ends up being the last value of i when your callbacks are evaluated.
Also note that you could use list.forEach.
Each event handler function you create in this code:
setHandlesByList: function (list) {
for (var i in list) {
var self = this;
$(document).on(list[i].name, function (e) {
list[i].callBack.call(self,e)
});
};
},
...has an enduring reference to list and i, not copies of them as of when the function is created. Since i ends up being the last property enumerated, all handlers end up referring to the same list entry.
Instead, create a builder function to create the callback (sorry, I can't recreate the indentation style you use, I've just used a fairly standard one):
setHandlesByList: function (list) {
var self = this;
for (var i in list) {
$(document).on(list[i].name, buildHandler(list[i]));
};
function buildHandler(entry) {
return function (e) {
entry.callBack.call(self,e)
};
}
},
Now, the function created closes over entry, the argument to the buildHandler call, rather than over list and i. Since entry (the argument) doesn't change, the handler works.
Note also that I've moved the var self = this; out of the loop, as it didn't vary from iteration to iteration and so had no business being in the loop.
Side note: You've said that the function receives an array. If so, for-in (with no safeguards) is not the correct way to loop through the entries in that array. More: Myths and realities of for..in
I have a requirement where I get the anchor tags id and based on the id I determine which function to execute.. so is there anything that suites below code
function treeItemClickHandler(id)
{
a=findDisplay(id);
a();
}
You can assign a function to a variable like so:
You can also return a function pointer from a function - see the return statement of findDisplay(id).
function treeItemClickHandler(id)
{
var a= findDisplay;
var other = a(id);
other();
}
function findDisplay(id)
{
return someOtherThing;
}
function someOtherThing()
{
}
Sure, functions are first class objects in JavaScript. For example, you can create a map (an object) which holds references to the functions you want to call:
var funcs = {
'id1': function(){...},
'id2': function(){...},
...
};
function treeItemClickHandler(id) {
if(id in funcs) {
funcs[id]();
}
}
As functions are treated as any other value, you can also return them from another function:
function findDisplay(id) {
// whatever logic here
var func = function() {};
return func;
}
functions are normal javascript values, so you can pass them around, (re)assign them to variables and use them as parameter values or return values for functions. Just use them ;) Your code is correct so far.
You can map between ids and functions to call in a number of ways.
One of the simpler ones is to create an object mapping ids to functions, and find the function to call from that object (this is in essence a nicer-looking switch statement).
Example:
function treeItemClickHandler(id)
{
var idMap = {
"some-id": findDisplay,
"another-id": doSomethingElse
};
if (!idMap.hasOwnProperty(id)) {
alert("Unknown id -- how to handle it?");
return;
}
// Call the corresponding function, passing the id
// This is necessary if multiple ids get handled by the same func
(idMap[id])(id);
}
function findDisplay(id)
{
// ...
}
function doSomethingElse(id)
{
// ...
}