17

I want to house a variable in a function. This variable will change state depending on user interaction. For example:

function plan_state(current){
    if (current != ''){
        state = current;
    }
    else {
        return state;
    }
}

When the document loads I call plan_state('me'), and when certain things happen I may call plan_state('loved'). The problem occurs when I run a function and want to check the current state:

alert(plan_state());

I get undefined back, but the value should be 'me' as I previously set this value on document load.

What am I doing wrong?

kjones
  • 1,339
  • 1
  • 13
  • 28
Daniel Hunter
  • 2,546
  • 6
  • 28
  • 34

2 Answers2

58

The function isn't stateful because the state variable is declared inside the function and therefore only exists for the lifetime of the function call. An easy solution would be to declare the variable globally, outside the function. This is bad bad bad bad.

A better approach is to use the module pattern. This is an essential pattern to learn if you're serious about javascript development. It enables state by means of internal (private variables) and exposes a number of methods or functions for changing or getting the state (like object oriented programming)

    var stateModule = (function () {
        var state; // Private Variable

        var pub = {};// public object - returned at end of module

        pub.changeState = function (newstate) {
            state = newstate;
        };

        pub.getState = function() {
            return state;
        }

        return pub; // expose externally
    }());

so stateModule.changeState("newstate"); sets the state

and var theState = stateModule.getState(); gets the state

Community
  • 1
  • 1
reach4thelasers
  • 26,181
  • 22
  • 92
  • 123
  • this is great. I think this is more of what i am looking for and even though i do not fully understand it.. YET... i am accepting it as answer as I was avoiding the global variable problem. Thanks. – Daniel Hunter May 04 '12 at 16:45
  • works!! and after implementing it and playing with it I sort of understand it.. had to change ChangeState to changeState by the way.. or vise versa. – Daniel Hunter May 04 '12 at 16:55
  • Glad it helped. Using that pattern you'll be a JavaScript ninja in no time! I fixed the function call case error thx for pointing it out. – reach4thelasers May 05 '12 at 00:28
  • 1
    You could have skipped the object entirely, have the API remain the same; something like [this](http://pastie.org/3863892) Edit: Now that I think about it, why do you need all this, instead of just having a `state` variable...and that's it? – Zirak May 05 '12 at 14:11
  • 1
    He's learning JavaScript/programming and the intricacies of scope. What would he have learned/gained from using a global variable besides becoming a bad developer? Your example would work but wouldn't help him understand the module pattern. We're all here to learn, right? – reach4thelasers May 06 '12 at 09:48
  • But isn't stateModule now also global? So where is exactly the difference than using just a string var stateModule and just assign some value to it? – kaiser Feb 02 '17 at 19:49
  • what's the difference of wrapping state in a function and exposing internal functions that mutate that state vs having those functions say in an ES6 module and global let variables at the top of your ES6 module and then export functions that can manipulate those local variable's state? – PositiveGuy Jul 12 '18 at 19:48
1

I believe the scope of your variable is too "low"; by defining the variable within the function, either as a parameter or explicitly as a var, it is only accessible within the function. In order to achieve what you're after, you can either implement the variable outside the scope of the function, at a more global evel (not recommened really).

However, after re-reading your question, it's slightly miss-leading. Would you not want to return state regardless of the current? I think you might be after something like so:

var state;
function plan_state(current)
{
    if (current != '' && current != state)
    {
        state = current;
    }
    return state;
} 

Alternative object structure:

function StateManager(state)
{
    this.state = state;

    this.getState = function(current)
    {
        if (current != '' && current != this.state)
        {
            this.state = current;
        }
        return this.state;
    }
}

// usage
var myStateManager = new StateManager("initial state here");
var theState = myStateManager.getState("some other state");
Richard
  • 8,110
  • 3
  • 36
  • 59
  • i thought by housing the variable in a function it was a way to avoid globals – Daniel Hunter May 04 '12 at 16:33
  • 1
    By declaring a variable within a function it isn't global, that's correct. However the lifespan of that variable is only active whilst the function is being used. When the function exists, the variable "no longer exists". You may want to consider an object :) – Richard May 04 '12 at 16:36