3

JavaScript setter updates the internal value at the reference but the return value is not correct.

var Game = 
{   
    get points() {
        return this._points;
},

    set points(x){        
       x = Math.min(x,25);

       this._points = x;   
       return this._points;
    }
};

Game.points = 10 ;

console.log(Game.points); // outputs 10

var updatedPoints = (Game.points = 60);

console.log(updatedPoints); // outputs 60
console.log(Game.points); // outputs 25

Expected value for 'updatedPoints' was 25 !

Any idea why this could be happening ? Can you suggest if there is a way to fix this ?

Reason to fix this: To make sure the JS code performs as expected , maintainibility !

sbr
  • 4,735
  • 5
  • 43
  • 49
  • @FelixKling one would expect the value for updatedPoints to be 25 ? – sbr Jan 23 '14 at 01:47
  • Yeah I understood your question now. But no, the result of an assignment expression is that value that was assigned (which is 60). – Felix Kling Jan 23 '14 at 01:48
  • I'd use a comma operator - it's shorter :P var updatedPoints = ( (Game.points = 60), Game.points ); – elad.chen Jul 25 '15 at 11:05

1 Answers1

6

The JavaScript simple assignement (=) returns the right value as per the specification (11.13.1). This behavior ignores whatever validation happens in your setter.

From the spec:

The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:

  1. Let lref be the result of evaluating LeftHandSideExpression.
  2. Let rref be the result of evaluating AssignmentExpression.
  3. Let rval be GetValue(rref).
  4. Throw a SyntaxError exception if the following conditions are all true:
    • Type(lref) is Reference is true
    • IsStrictReference(lref) is true
    • Type(GetBase(lref)) is Environment Record
    • GetReferencedName(lref) is either "eval" or "arguments"
  5. Call PutValue(lref, rval).
  6. Return rval.

So there is no way to "fix" your issue as it is by design. Checking Game.points should be enough.

dee-see
  • 23,668
  • 5
  • 58
  • 91
  • I am changing an object to getter-setter format, but this can have side effects at the existing references in the legacy code if a reference is made like the way i showed above. – sbr Jan 23 '14 at 01:57
  • @sbr Ah I see. Then yeah, you might have an issue but I'm afraid there is no way around it. Though one might argue that modifying the value in the setter is bad practice since the caller does not expect that to happen. Throwing an error if `x > 25` would avoid the issue at hand, if you can live with that kind of behavior. Good luck! – dee-see Jan 23 '14 at 02:02
  • The main reason of implementing it through a setter is validation and coercion. Can you think of a better way to attach a validator method to every assignment ? something concise like this one. Thanks – sbr Jan 23 '14 at 02:07
  • Well usually a validation does not modify input, it checks if it is valid and blocks the input in some way if it isn't. That's why I suggested throwing an exception instead of modifying the value. Other than that I don't know. Hard to tell what would make sense for you without really diving in your project... – dee-see Jan 23 '14 at 02:10