Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performing assignment operations on an object

Tags:

javascript

Example JSFiddle so you can get a better idea of what is going on http://jsfiddle.net/brsXL/3/ (open your console and view the logged vars object).

I am building a parser and computer for a specific subset of maths in JavaScript, it takes an expression as a string from the user and allows them to use variables. To keep my computational logic simple but allow for the use of variables I have created an object that acts like a number but has the bonus of being passed by reference.

var Variable = function(value) {
    this.value = value || null;
}
Variable.prototype.valueOf = function() {
    return this.value;
}

This works so that:

var a = new Variable(10);
console.log(a + 2); // = 12
console.log(a / 2); // = 5

However as soon as I wish to perform any form of assignment operation such as += the object is lost and gets replaced by the result of the operation against the object's value property. e.g.

var a = new Variable(10);
console.log(a += 2); // = 12
console.log(a); // = 12

The reason I need it to work like this is because I want to use the same function to handle both numbers and variables. I could add code to each assignment operation but this feels sub-optimal to me, e.g.

var ops = {
   "+=" : function(a, b) {
      if (a instanceof Variable) {
         a.value += b;
      } else {
         a += b;
      }
      return a;
   },
   ...
}

But I'd much rather write:

var ops = {
   "+=" : function(a, b) {
      return a += b;
   },
   ...
}

Can this be done?

like image 832
George Reith Avatar asked Oct 22 '13 23:10

George Reith


1 Answers

I'd much rather write:

function(a, b) {
    return a += b;
}

Can this be done?

No. It's impossible to pass a Reference value as a single variable. You always will need to use object properties. a is always local-scoped in your function, so changing it won't affect the outer world. And I'd discourage you from trying to make your operators functions that operate on higher-scope variables…

I think in your case it's quite fine to use an explicit test for variables, because the assignment operator has to do that actually. You cannot assign to literals or other values, only to variables. It might even be

var ops = {
   "=" : function(a, b) {
      if (a instanceof Variable) {
         a.value = +b; // cast b to a number (from whatever it is)
         return a;
      } else {
         throw new Error("Invalid assignment to non-variable "+a);
      }
   },
   ...
}

Also, to avoid code duplication you might not write out all the compound assignment operators. Define them in a generic way:

["+", "-", "*", "/"].forEach(function(op) {
    ops[op+"="] = function(a, b) {
        return ops["="].call(this, a, ops[op].call(this, a, b));
    };
});

(Updated jsfiddle demo)

like image 127
Bergi Avatar answered Oct 11 '22 11:10

Bergi