erfling
erfling

Reputation: 409

Javascript property as reference to other object's property

Is there a way to assign properties of one object as references to the properties of another, and do so dynamically? Note that in the for loop, I've skipped any property that has the same name as the second object. I'm working on a framework that will cache JSON as objects with behaviors and allow ORM kind of behavior, where I can grab cached objects and collections as properties of other cached objects. I need to skip certain properties to avoid circular reference.

var obj1 = {
    prop1: "hey",
    obj2:"you",
    prop2: "come over here"
}

var obj2 = {}

for(var prop in obj1){
    if(prop != 'obj2'){
        obj2[prop] = obj1[prop];
    }
}
console.log(obj1);
console.log(obj2);

obj1.prop2 = "come on, man";

console.log(obj1);
console.log(obj2);
//obj1 is unchanged in output.  I would like to be able to update it by mutating obj2's properties

fiddle: http://jsfiddle.net/6ncasLb0/1/

If this is not possible, is it possible to remove or mutate a property of a reference without mutating the original object? I know, probably not. Just a shot in the dark.

Upvotes: 0

Views: 176

Answers (1)

Icepickle
Icepickle

Reputation: 12796

I guess the closest you can get to it, is to make sure the property you are changing it the same property you are getting on both objects, so you would need to do some work to make sure they "know" each other when they are instantiated (eg, clone from the original object)

As an example, you could use a simplified model like this, any properties marked in its creation would also update the original object, though new properties defined on the object should be fine). Note that enumrating and just referencing the properties wouldn't work, at least not with strings (objects would change when copied from 1 object to another)

;
(function(namespace) {
  function addProperty(obj, property, valueholder) {
    Object.defineProperty(obj, property, {
      get: function() {
        return valueholder[property];
      },
      set: function(val) {
        valueholder[property] = val;
      },
      enumerable: true,
      configurable: false
    });
  }

  var model = namespace.model || function(options) {
    if (typeof options === 'undefined') {
      options = {};
    }
    var propHolder = options.container || {},
      prop;
    if (typeof options.props != null) {
      for (prop in options.props) {
        if (options.props.hasOwnProperty(prop)) {
          addProperty(this, prop, propHolder);
          propHolder[prop] = options.props[prop];
        }
      }
    };

    namespace.model.prototype.clone = function() {
      var options = {
          props: {},
          container: propHolder
        },
        prop;
      for (prop in this) {
        if (this.hasOwnProperty(prop)) {
          options.props[prop] = this[prop];
        }
      }
      return new namespace.model(options);
    };

    namespace.model.prototype.toString = function() {
      var prop, msg, props = [];
      for (prop in propHolder) {
        if (propHolder.hasOwnProperty(prop)) {
          props.push(prop + ': "' + this[prop].toString() + '"');
        }
      }
      return '[Model] {' + props.join(', ') + '}';
    }

    return this;
  };

  namespace.model = model;
}(window));

var obj1 = new model({
  props: {
    prop2: "come over here"
  }
});
obj1.prop1 = 'Hey';
obj1.obj2 = 'You';
obj1.test = {
  a: 10
};

var obj2 = obj1.clone();

console.log('-- before changes --');
console.log(obj1.toString());
console.log(obj2.toString());

obj2.prop2 = "come on, man";
obj2.prop1 = "won't change";
obj2.obj2 = "also not";
obj2.test.b = "both have this now";

console.log('-- after changes --');
console.log(obj1.toString());
console.log(obj2.toString());

console.log(obj1.test);
console.log(obj2.test);

Upvotes: 2

Related Questions