0

I have a module pattern with a variable setting the currentPlayer to 1. I use a function expression to toggle that variable

 const game = (() => {
    let currentPlayer = 1;

    const toggleCurrentPlayer = () => {
        if (currentPlayer == 1){
            currentPlayer = 2 ;
        }
        else {
            currentPlayer = 1;
        }
    };
    return {currentPlayer, toggleCurrentPlayer};
})();

If I run game.currentPlayer it logs 1, I then run game.toggleCurrentPlayer(), and it doesn't change currentPlayer as intended, it still returns 1.

However, changing the toggleCurrentPlayer() function using this, seems to be able to change the variable successfully

function toggleCurrentPlayer(){
    if (this.currentPlayer == 1){      
        this.currentPlayer=2;
    }
    else if (this.currentPlayer == 2){
        this.currentPlayer=1;
    }
};

I know function declarations and function expressions have different meanings for the keyword this, but why would the toggleCurrentPlayer() only work properly with the this keyword and not be able to set the variable on its own?

spacing
  • 730
  • 2
  • 10
  • 41
  • 1
    The difference has nothing to do with the way `toggleCurrentPlayer` is declared. It's about modifying a local variable vs. modifying an object property. – Bergi Aug 10 '20 at 23:57
  • @Bergi So I can only modify the object property inside the module, but I cannot assign a new value to the variable inside the module? – spacing Aug 10 '20 at 23:59
  • 2
    Your first code does toggle the local variable just fine. The problem is that the `game.currentPlayer` property is not a live view on the variable, it just keeps the value that you created initially. – Bergi Aug 11 '20 at 00:01
  • 1
    (And you've got it backwards: any code from outside the module can assign the object property using `game.currentPlayer = 3;`, but only the code inside the module scope can access and assign the local variable `let currentPlayer`) – Bergi Aug 11 '20 at 00:03
  • I wonder how he can change the currentPlayer variable inside game – CHANist Aug 12 '20 at 06:17

1 Answers1

2

When the function does

return {currentPlayer, toggeleCurrentPlayer};

It copies the initial value of the currentPlayer variable into the object.

The returned object contains the value of the variable, not a reference to the variable itself. Reassigning the variable has no effect on the object.

What you can do instead is create an object inside the function, and modify that.

const game = (() => {
  let obj = {
    currentPlayer: 1,
    toggleCurrentPlayer: () => {
      if (obj.currentPlayer == 1) {
        obj.currentPlayer = 2;
      } else {
        obj.currentPlayer = 1;
      }
    }
  };
  return obj;
})();

console.log(game.currentPlayer);
game.toggleCurrentPlayer();
console.log(game.currentPlayer);

Another way to do it is with a getter function that retrieves the variable.

const game = (() => {
    let currentPlayer = 1;

    const toggleCurrentPlayer = () => {
        if (currentPlayer == 1){
            currentPlayer = 2 ;
        }
        else {
            currentPlayer = 1;
        }
    };
    const getCurrentPlayer = () => currentPlayer
    return {getCurrentPlayer, toggleCurrentPlayer};
})();

console.log(game.getCurrentPlayer());
game.toggleCurrentPlayer();
console.log(game.getCurrentPlayer());
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • In that case you wouldn't even need the IIFE – Bergi Aug 11 '20 at 00:04
  • Without the IIFE where would I get a scope for `obj`? I could change it to use `game.currentPlayer` in the toggle function. – Barmar Aug 11 '20 at 00:06
  • Oops, I missed that you had not used `this` in a method but an arrow function closing over `obj`. But yeah, given that `game` is `const` anyway, using that seems fine as well. – Bergi Aug 11 '20 at 00:12
  • The getter function approach seems more appropriate though, here, and nicely demonstrates the issue that the OP had. – Bergi Aug 11 '20 at 00:13
  • I see some pegagogical value to separating the external variable from the internal code. – Barmar Aug 11 '20 at 00:13
  • that was very helpful, can you just help me understand why the the getter function works? – spacing Aug 11 '20 at 16:24
  • 1
    It's accessing a variable saved in the closure. – Barmar Aug 11 '20 at 16:25
  • 1
    See https://stackoverflow.com/questions/111102/how-do-javascript-closures-work – Barmar Aug 11 '20 at 16:27