0

I wanted to create a local function variable for a specific use case without polluting my global object scope. I will be calling doThis() multiple times, but want to keep the local counter value.

So, do this:

TaskHandler = {

     doThis : function () { 
            myVariable+= (myVariable) ? var myVariable = 0;
            doSomethingWithVariable(myVariable);

            // OR

            var myVariable = myVariable+=1 || 0;

            // OR

            var myVariable = (myVariable) ? myVariable+=1 : 0;
     }

Instead of:

TaskHandler = {
     myVariable : 0,

     doThis : function () { 
            this.myVariable++;
            doSomethingWithVariable(this.myVariable);
     }

Is this possible?


TaskHandler = {

    doThis : function (requirement) {

        var track_index = (function () {
           var myVariable = 0;
           return function () {
               ++myVariable;
           }
        })();

       doSomethingWithVariable(track_index);
   },

}

    TaskHandler = {

        doThis : function () {

         (function () {
            console.log('called'); // This is called
            var myVariable = 0;
            return function () {
                ++myVariable;
                console.log(myVariable); // This is NOT called
            }
        })();
   }
}

Last edit:

TaskHandler = {

    someFunction : function (myObject) {

        this.doThis(myObject).counter();
    },

    doThis : function (myObject) {

         return {
            counter : (function (myObject) {
                var myVariable = 0;
                return function () {
                    ++myVariable;
                    console.log('index', myVariable); //not incrementing
                }
            })(myObject)
        }
    }
}
user3871
  • 12,432
  • 33
  • 128
  • 268

3 Answers3

2

You need a closure: a function that is declared within a scope of a local variable, and that therefore "remembers" this variable later on.

For example:

TaskHandler = {

    doThis : (function () {
        var myVariable = -1;

        return function () {
            ++myVariable;
            doSomethingWithVariable(myVariable);
        };
    })(),

    // ... rest of TaskHandler's properties ...
 }

(where (function () { ... })() is an immediately-invoked function expression).

Community
  • 1
  • 1
ruakh
  • 175,680
  • 26
  • 273
  • 307
  • Thanks for this. Can you see above? I would prefer to not call `doSomething...()` within the closure. Can't I maintain the count within the closure and return it to the outside and use it as such? – user3871 Jan 25 '16 at 01:36
  • so, you want to access a variable defined within a closure outside of the closure? – Jaromanda X Jan 25 '16 at 01:38
  • @JaromandaX okay. Please see edit 2 above. Why isn't the inner `console.log()` called? – user3871 Jan 25 '16 at 01:43
  • Re: "I would prefer to not call `doSomething...()` within the closure": Why? I can't think of any reason for such a preference. – ruakh Jan 25 '16 at 01:43
  • @Growler - don't ask me, not my concern – Jaromanda X Jan 25 '16 at 01:44
  • 1
    Re: your edit: The `console.log('called')` statement is run just before you *create* the closure, i.e., before `TaskHandler` and `doThis` even exist. The `console.log(myVariable)` statement is run when you call `TaskHandler.doThis()`. Your initial question demonstrates that the latter is, in fact, the behavior you want. (Also, your edit has a `;` where you presumably meant a `,`, but I'll chalk that up to a copy/paste error.) – ruakh Jan 25 '16 at 01:45
  • @ruakh okay thank you. Took me a sec to understand. but got it. – user3871 Jan 25 '16 at 01:49
  • @ruakh How can I pass a variable into `doThis()`? I've tried `doThis : (func... { })(valueToPass)` then call it outside as `doThis(valueToPass)` but it's undefined – user3871 Jan 25 '16 at 02:56
  • @ruakh plz see above. Guess I don't get it. I dont want to define the closure on `doThis()` as I need it for other things. I'd rather define the closure within `doThis` and access the stored index as needed. But the value isn't incrementing – user3871 Jan 25 '16 at 03:05
  • @Growler: In the version in your latest edit, `doThis` doesn't close over any variables. Each call to `doThis` creates a fresh closure and returns it (wrapped in an object). You can see this by writing something like `var foo = this.doThis(); foo.counter(); foo.counter();`. To fix this, you need to write something like what I wrote in this answer. – ruakh Jan 25 '16 at 03:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101550/discussion-between-growler-and-ruakh). – user3871 Jan 25 '16 at 03:45
  • @ruakh okay, I've done that here: http://stackoverflow.com/questions/34984744/how-can-i-pass-a-variable-into-a-iife. Now I'm unable to pass in a param – user3871 Jan 25 '16 at 03:46
  • @Growler: And, it looks like you've already gotten a good answer there. :-) – ruakh Jan 25 '16 at 03:59
0

You can check if the value is undefined, as such:

TaskHandler = {
    doThis: function() {
        if (typeof this.myVariable === 'undefined') {
            this.myVariable = 0;
        }
        doSomethingWithVariable(this.myVariable);
    }
}
0

You have to put your var somewhere, but it does not need to be in global scope or as a filed of your object. Considering you are using plain ES5, in a browser, so I do exclude all the bells and whistles of ES6's new features, you can do something like this:

(function () {
  var myVariable = 0;
  window.taskHandler = {
    doThis : function () { 
      myVariable++;
      doSomethingWithVariable(myVariable);
    }
  }
})()

So, the myVariable is not exposed and your global object is not "polluted".