2
votes

I want to be able to create a new object that is effectively an alias of an existing object, except with a new method added to the new object that is not added to the original aliased object. I'm new to javascript, so I don't know if something like what I want already exists and/or is easily implimented. To give a simplified example of my use case consider this:

So say I have a shared object foo. For Angular types imagine a service or factory. It looks like this:

var foo(){
    var array: {},
    updateArray: function(value){ array.push(value)},
    saveFoo: function(parameters){
         //save logic
    }
}

say I get sick of constantly passing huge arrays of parameters to foo's save method, so I decide to add a wrapper to foo with some extra logic to make my life easier

function addSaveableParameters(foo){
      var savedParams={}
      foo.setParam = function(parameter){
          savedParams.push(parameter);
      }
      foo.save = function(){
          foo.save(savedParams);
      }

      return foo
}

foo=addSaveableParameters(foo);

now If I save a parameter one at a time to foo by simply calling my little helper function to add the saveParameter method.

However, I'm working with a shared object, an angular factory specifically. If I call addSavableParameters I'm modifying the one version of the foo factory everyone has. More importantly if I have two people that are using my foo service and they each call saveParameters they will both save a parameter to the same shared foo object, which will likely cause them both to be confused when they later call save() and find a second parameter they never added exists on foo.

One option to handle this would be to clone foo. However, the original shared foo had an array that others could modify. I want to be aware of changes to that array, if someone changes the original foo's array I want to see those changes, and if I change foo I want others to see my changes. By cloning foo I would create a new instance which has a mere copy of foo's array as of the time it was cloned, it doesn't stay up to date with new changes to the original shared foo's array.

If I wanted to both stay up to date with changes to Foo's array and have my own separate version of savedParameters I could wrap foo instead:

function addSaveableParameters(foo){

      var newFoo={
          savedParams: {},
          setParam: function(parameter){
               savedParams.push(parameter);
          },
          save: function(){
             foo.save(savedParams);
          },
          save: function(parameters){
               foo.save(parameters);
          },
          updateArray: function(value){
               foo.updateArray(value);
          }
        }

   return newFoo;
}

foo=addSaveableParameters(foo);

now I can create my own version of foo, which reflects all changes to the old foo and can generally be used as if it was an alias to the old foo, but which allows me to set saved parameters only on my version of foo.

However, I had to manually wrap functions to do it. If I have a really large object I may find myself wrapping dozens of functions. I also need to know every function foo has ahead of time so I can create a wrapper to it. If someone decides to add a new method to foo later my wrapper won't have the new method.

Is there a convenient way in javascript to make this sort of wrapper logic occur automatically without being written to a specific object? So I can simply call wrapper(foo) and I'll get back an object with all of foos methods and variables, which are still aliased to foo, but where I can add methods which only exist on my version of the wrapped foo object?

1
Depending on how complex/large your object is, and how often you do it, you could use jQuery's extend (api.jquery.com/jquery.extend). Something like $.extend({}, object1, object2); will merge two objects. Or you could use the command to create a deep copy and then start adding to it. - Robin Nabel
@RobinNa I don't think this would work would it? The deep copy either modified the original, leading to issues if multuple people wish to have their own version of saveParams, or is a new copy that, while originally a perfect copy of the original array, ultimately is no longer referencing the same array and thus would get out of sink with changes made to the original array not being reflected in the extended object. - dsollen
To try summarizing your issue you are concerned about concurrent operations in JavaScript and you are trying to clone the object to have private variables, although you would still need to deal with merging the objects back together again? - Enzey
I think yes, I need to make sure I stay consistent with changes to the provider. in my actual use case I'm trying to add a transformation hook toadd common methods to restangularized objects. There are dozens of methods on the original object after being restangularized, and transformers may add additional methods for specific routes. In short I don't know exactly what the object I get in the transformer looks like, only that I want to maintain it's existing behavior while adding on my helper methods (which in this case is almost exactly the same as the saveParameter method above) - dsollen
Minor observation: you're initializing your array variables to an empty object ({}), and then calling array methods on them (e.g., push). I'd be surprised if that worked... - Heretic Monkey

1 Answers

1
votes

You probably want to use Javascript classes, which simulate the same classes you see in object-oriented languages.

function Foo() {
  // private vars
  var parameters; 

  // public methods
  this.setParam = function(_params) {
    parameters = _params;
  };

  this.save = function() {
    // save parameters
  }
}

And then you can instanciate as many foos as you want

var foo1 = new Foo();
var foo2 = new Foo();

foo1.setParams( hugeObject );
foo1.save();