25

I am looking for a good technique to get away from what I am tempted to do: to set a global variable.

The first time someone runs a function by clicking a button it triggers an initial function to turn a few things into draggables. Later, if they click the button a second time I want to determine if the init function has been initialized, and if so to not call it again. I could easily do this by setting a global variable from the init function and then checking that variable from the click function, but I'm wondering how to do this without setting a global variable. I would really like an example of a way to do this.

codelove
  • 1,988
  • 5
  • 26
  • 36

6 Answers6

29

You could add a property to the function:

function init() {
    init.called = true;
}

init();

if(init.called) {
    //stuff
}
Levi Hackwith
  • 9,232
  • 18
  • 64
  • 115
22

While @Levi's answer ought to work just fine, I would like to present another option. You would over write the init function to do nothing once it has been called.

var init = function () {
   // do the initializing

    init = function() {
        return false;
    }
};

The function when called the first time will do the init. It will then immediately overwrite itself to return false the next time its called. The second time the function is called, the function body will only contain return false.

For more reading: http://www.ericfeminella.com/blog/2011/11/19/function-overwriting-in-javascript/

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Amith George
  • 5,806
  • 2
  • 35
  • 53
  • This is smart, while i will use Jason's answer for simplicity I will definitely use this technique in the future – codelove Jul 02 '12 at 19:55
2

Why don't you just check to see if your draggables have a class of draggable on them?

if ($('.mydiv').is('.draggable')) {
     //do something
}
Jason
  • 51,583
  • 38
  • 133
  • 185
  • Thanks for this Jason! ended up using a ! symbol to check if it wasn't yet a draggable but basically the solution i needed. – codelove Jul 02 '12 at 19:54
  • 1
    yup, no problem. so if this is what you used, why didn't you pick it as accepted? :D – Jason Jul 02 '12 at 21:05
  • I tried using it with a ! but for some reason it was always registering as not draggable... so went for Levi's solution.. Sorry there were so many methods to choose from! lol – codelove Jul 02 '12 at 21:40
  • no worries. the main problem with the other techniques that apply properties (unnecessary) or overwrite functions (destructive) is that they don't provide any other useful information. enough information is already available to you, why create more things to manage? my method is non-destructive and uses currently-available information. – Jason Jul 02 '12 at 22:42
2
Function.prototype.fired = false;

function myfunc() { 
    myfunc.fired = true; 
    // your stuff
};

console.log(myfunc.fired) // false

myfunc();

console.log(myfunc.fired) // true
Cau
  • 21
  • 1
1

What you could do is unhook the init function from the prototype.

​var Obj = function () {
    this.init = function () {
        document.write("init called<br/>");
        this.init = null;
    }
}
var o = new Obj();
if (o.init) document.write("exists!<br/>");
o.init();
if (o.init) document.write("exists!<br/>");
o.init();

​ The first if will be true and print exists! but since the function removes itself, the second if will fail. In my example, I call the second init unconditionally just to show that nothing will happen, but of course you could call it only if it exists:

if (o.init) o.init();

http://jsfiddle.net/coreyog/Wd3Q2/

Corey Ogburn
  • 24,072
  • 31
  • 113
  • 188
  • wow there are a lot of solutions to this task! its hard to determine which route to take, lol – codelove Jul 02 '12 at 19:57
  • There are many quality solutions. It's worth noting in mine that `init` is incapable of being called again. Many of these others require that some variable be checked and if you don't check it, you can still call it. – Corey Ogburn Jul 02 '12 at 19:59
1

The correct approach is to use the Javascript Proxy APIs to trap the function calls using apply handler.

const initFun = (args) => {
  console.log('args', args);
}
const init = new Proxy(initFun, {
  apply(target, thisArg, args){
    target.calls = target.calls ? target.calls + 1 : 1;
    return target.apply(thisArg, args);
  }
});

init('hi');
console.log(init.calls); // 1
init('hello');
console.log(init.calls); // 2
ahmadalibaloch
  • 5,851
  • 2
  • 50
  • 59