klinore
klinore

Reputation: 2739

Why doesn't my variable's value change when a variable its value relies on also changes?

After hitting the increment button in my code below, y is equal to 7, but z stays equal to 7 instead of changing to 8.

Why don't JavaScript variables update within other variables? Is there a solution to this problem?

<body>
    <script>
        var y=6;
        var z=1+y;
    </script>
    <button onclick="y++">Increment</button>
    <button onclick="alert(y)">What is y?</button>
    <button onclick="alert(z)">What is z?</button>
</body>

Upvotes: 3

Views: 1243

Answers (4)

bfavaretto
bfavaretto

Reputation: 71918

The value held on variable z is calculated the moment you assign it to the variable:

var z=1+y;

If you want it to change, you have to update it manually:

<button onclick="z=++y+1">Increment</button>

Most computer languages behave like that, I believe.


In JavaScript and other languages you can use "getters" and "setters" to achieve what you want, but the code will become more complex. Judge if you really think it's necessary:

<body>
    <script>
    var vals = {
        _y : 0,
        z : 0,
        set y(val) {
            this._y = val;
        },
        get y() {
            this.z = this._y + 1
            return this._y;
        } 
    }
    vals.y = 6;
    vals.z = 1 + vals.y;
    </script>
    <button onclick="vals.y++">Increment</button>
    <button onclick="alert(vals.y)">What is y?</button>
    <button onclick="alert(vals.z)">What is z?</button>
</body>

https://jsbin.com/udediy/1/edit


Another, simpler solution is to just use a function. That would work well for the example you gave:

<body>
    <script>
    var y=6;
    var z = function() {
        return 1+y;
    }
    </script>
    <button onclick="y++">Increment</button>
    <button onclick="alert(y)">What is y?</button>
    <button onclick="alert(z())">What is z?</button>
</body>

https://jsbin.com/ojorax/1/edit

Upvotes: 4

HMR
HMR

Reputation: 39270

y is evaluated when you set z. At that time y is 6 so z is 7. When you increase y then z is not re evaluated (as you've found out).

y=1;
z=++y;//increment y and assign the value to z
 // z will be 2;
z=y++;//set z to the value of y and then increment y
   // z is now 2 and y is 3

If you want one variable to be dependent on the value of another variable you can't just assgin new values to them. You have to use getters and setters functions:

var myObj={
  y:0,
  x:0,
  setY:function (value){
    this.y=value;
    this.x=value+1;
  },
  setX:function (value){
    this.x=value;
    this.y=value-1;
  }
}
myObj.setY(4);
console.log(myObj.x);//=5
myObj.y=2;//breaks setting x, you have to use setters
console.log(myObj.x);//=5

As you can see the line myObj.y=2 breaks setting z so you can't assign values to either myObj.y or myObj.z without breaking it.

To prevent this from happening you have to make x and y private. In JavaScript you can simulate private variables using closures.

A warning for the folling code: if you plan to create multiple instances of your object use constructor functions and have private variables using code conventions (like _privateVar) instead of real privateness since JS doesn't support it unless you're planning on not using prototype.

var myObj=(function(){
  var x=0;// x and y only exist in the funciton body
  var y=0;// you cannot access them in myObj.x or .y
  return{
    setX:function(value){
      //maybe check if value is a number here
      x=value;
      y=value-1;
    },
    setY:function(value){
      //maybe check if value is a number here
      y=value;
      x=value+1;
    },
    getX:function(){
      return x;
    },
    getY:function(){
      return y;
    }
  }
})();
myObj.setX(6);
console.log(myObj.getY());//logs 5
myObj.y=22;
console.log(myObj.getY());//still logs 5

Using bfavaretto's syntax with get and set you can assign new values but internally JavaScript will use the getters and setters functions. This does not work in older browsers like IE8 and under.

var myObj={
  _y:0,
  _x:0,
  set y(value){
    this._y=value;
    this._x=value+1;
  },
  get y(){
    return this._y;
  },
  set x(value){
    this._x=value;
    this._y=value-1;
  },
  get x(){
    return this._x
  }
}
myObj.x=4;
console.log(myObj.y);//=3

Upvotes: 3

Dan455
Dan455

Reputation: 352

One way to do it is to wrap the variable in an object, which is passed by reference rather than by value:

var obj = { y : 6 };
var obj_2 = obj;
alert(obj.y); //6
alert(obj_2.y); // 6
obj.y++;
alert(obj.y); // 7
alert(obj_2.y); // 7`

Upvotes: 1

Arun P Johny
Arun P Johny

Reputation: 388316

once you assign the value of z = 1 + y z references a different location and there is no further relation between z and y

Upvotes: 1

Related Questions