Search code examples
javascriptclosuresfunction-expression

Updating values with a function, returning not working


So I am using a function to update my values, but I can't then get them back. I see values don't get updated, but is there any way of saving them as a reference to the return of the function.

function Amphibia(wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {

        this.speed = 0;
        this.mode = mode;

        var amphibiaWheel = new PropulsionUnits.Wheel(wheelRadius);
        var amphibiaPropeller = new PropulsionUnits.Propeller(finsPerPropeller, propellersSpinDirection);

        this.changeMode = function () {
            if (mode == "land") {

                mode = "water";
            }

            else if(mode == "water") {

                mode = "land";
            }

            return {

                mode: mode
            }
        }

        this.accelerate = function() {
            if(this.mode == "water"){
                this.speed += amphibiaPropeller.acceleration;
            }
            else if(this.mode == "land"){
                this.speed += 4*amphibiaWheel.acceleration;
            }
        }

        this.changePropellerSpinDirection = function() {

            amphibiaPropeller.changeSpinDirection();
        }

        return {

            speed: this.speed,
            mode: this.mode,
            changeMode: this.changeMode,
            accelerate: this.accelerate,
            changePropellerSpinDirection: this.changePropellerSpinDirection
        }

    }

So here I am experiencing problems with changing the mode and the changeMode function expression. Mode in it should refer to this.mode and then I should be able to update the value.


Solution

  • mode and this.mode are not the same. In your functions you are checking/setting values on mode and this.mode, separately.

    Either should work fine, as long as you're using one or the other, in the same place, the same way.

    Edit

    var Amphibia = function (wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
    
        var amphibia = this,
            MODES = { LAND : "land", WATER : "water" };
    
        amphibia.getMode = function () { return mode; };
        amphibia.setMode = function (val) { mode = val; };
    
        amphibia.changeMode = function () {
            amphibia.setMode((mode === MODES.LAND) ? MODES.WATER : MODES.LAND);
        };
    };
    
    
    var amphibia = new Amphibia("", "", "", "land");
    
    amphibia.getMode();    // "land"
    amphibia.changeMode();
    amphibia.getMode();    // "water"
    

    mode is now 100% private, and unique to that instance.

    If you don't need it to be, then you can append it to this, if you'd like.

    But here's your problem:

    var Amphibia = function () {
        var amphibia = this,
            amphibiaPropeller = new Propeller(  );
    
        // mode, getMode, setMode, etc...
    
        amphibia.accelerate = function () {
            if (amphibia.getMode() === "water") {
                this.speed += amphibiaPropeller.acceleration;
            }
        };
    };
    
    var amphibia = new Amphibia();
    var bob = { speed : 0 };
    bob.accelerate = amphibia.accelerate;
    
    bob.accelerate();
    // if amphibia.mode === "water", bob.speed += amphibiaPropeller.acceleration
    
    bob.speed; // === amphibiaPropeller.acceleration
    
    
    setTimeout(amphibia.accelerate, 10); // call amphibia.accelerate in ~10ms
    // if amphibia.mode === "water", window.speed += amphibiaPropeller.acceleration
    window.speed; // === amphibiaPropeller.acceleration
    

    Be consistent in how you refer to things.
    Don't mix self and this, unless you intend to get those side-effects...
    And unless you have a very, very good reason to do so (like you're building a framework/engine, not the modules/classes of the game/simulation which use the engine; ie: the difference between building jQuery and building something with jQuery), then you should probably avoid doing it.

    If you have closure ("private") state that you want to expose to the outside world, all you need is a function that returns that value, and/or one that sets it.
    All of a sudden, the differences between self and this and what is which, when, all go away, as long as you are consistent with how you use them, and you know what the value of this is going to be, every time you call the method.

    Notice I'm not returning anything...
    When I use new, the value of this (amphibia/self) gets returned by default.

    If you want to use private values, and return a "Revealing Module" (which is what I typically prefer), then you can simply do this:

    var Amphibia = function (mode) {
        var getMode = function () { return mode; },
            setMode = function (val) { mode = val; },
            changeMode = function () {
                setMode( mode === "water" ? "land" : "water" );
            };
    
        return {
            getMode : getMode,
            setMode : setMode,
            changeMode : changeMode
        };
    };
    
    var amphibia = new Amphibia("water");
    // `new` won't do any harm, but you can also not use it,
    // without it saving everything to `window`
    
    amphibia.getMode(); // "water"
    amphibia.changeMode();
    amphibia.getMode(); // "land"
    

    Or, maybe if you want that to look a little more like a module/component...

        return {
            mode : { get : getMode, set : setMode, switch : changeMode }
        };
    
    
    var amphibia = Amphibia("land");
    amphibia.mode.get(); // "land"
    amphibia.mode.switch();
    amphibia.mode.get(); // "water"
    
    
    var bob = { };
    bob.switchAmphibiaMode = amphibia.mode.switch;
    bob.switchAmphibiaMode();
    amphibia.mode.get(); // "land"
    
    setTimeout(amphibia.mode.switch, 10);
    setTimeout(function () { console.log(amphibia.mode.get()); }, 20);
    
    // 10ms amphibia.mode.switch();
    // 20ms console.log(amphibia.mode.get());
    //          > "water"
    

    ...or whatever other structure you'd like.
    You don't need a this at all.

    But this is something to be very, very careful with in JavaScript, because the meaning of this changes every time you call a function, and if half of the code uses this and half uses self, you're bound for some surprises.