1

Consider the following:

var obj1 = {"value":"one"};
var obj2 = obj1;
console.log(obj2.value+"\n");    // prints "one"
obj1 = {"value":"two"};
console.log(obj2.value+"\n");    // still prints "one"

I understand the reason for this, in the first two lines, obj1 and obj2 are references which both point to the same object, {"value":"one"}, somewhere in memory. When obj1 is assigned to a different object, {"value":"two"}, obj2 is still pointing to the same object {"value":"one"} in memory.

What I am looking for is a way to coerce the {"value":"one"} object in memory to "redirect" its callers to the {"value":"two"} object. In other words, I am looking for a way to manipulate the {"value":"one"} object so that the obj2 variable would ultimately point to the {"value":"two"} object, without reassigning the obj2 variable:

var obj1 = {"value":"one"};
var obj2 = obj1;
console.log(obj2.value+"\n");    // prints "one"
// ...some code to manipulate the `{"value":"one"}` object in memory
// so that *any* references which originally pointed to the
// `{"value":"one"}` object now point to the `{"value":"two"}`
// object, like a sort of "redirection".  This would be done
// without ever explicitly reassigning the references.
console.log(obj2.value+"\n");    // now prints "two"

Is there a way to accomplish this?

The actual application involves some pretty complex Mozilla code which would encumber this thread to try and explain, so I am asking this as a general theory question.

EDIT: CONCLUSION:

"No" is the most correct answer to the actual question, torazaburo's comment below states this well. However I felt that Patrick's answer, using a proxy, comes the closest to accomplishing this, so I accepted his answer. I will add that while proxies are very powerful tools, they are not the same as the actual target object, and there are some limitations.

KevinHJ
  • 1,014
  • 11
  • 24
  • This is a basic issue of object identity. An object is itself, and always will be. There may be other solutions to your underlying problem, but changing an object's identity on the fly--swapping out an object from underneath itself--is not one of them. –  Jul 28 '16 at 19:48
  • it's easy to get `console.log(obj2().value+"\n");` operational as-described. You might be able to use a getter or proxy to avoid the parens.... – dandavis Jul 28 '16 at 19:56

3 Answers3

3

Check out proxies. You could use the get and set to dynamically reference a base object of your choosing, exposing proxies as the free-floating references you want to implicitly update. Here's an example:

function Proxyable(target) {
  this.target = target;
  this.proxy = new Proxy(this, Proxyable.handler);
}

Proxyable.prototype.getReference = function () {
  return this.proxy;
};

Proxyable.prototype.setReference = function (target) {
  this.target = target;
};

Proxyable.handler = {
  get: function (proxyable, property) {
    return proxyable.target[property];
  },
  set: function (proxyable, property, value) {
    return proxyable.target[property] = value;
  }
};

// original object
var original = { value: ['one'] };
// have to create a namespace unfortunately
var nsp = new Proxyable(original);

// reference the ref value of the namespace
var ref1 = nsp.getReference();
var ref2 = nsp.getReference();

// same references (not just values)
console.log(ref1.value === original.value);
console.log(ref2.value === original.value);

// hot-load a replacement object over the original
var replacement = { value: ['two'] };
// into the namespace
nsp.setReference(replacement);

// old references broken
console.log(ref1.value !== original.value);
console.log(ref2.value !== original.value);
// new references in place
console.log(ref1.value === replacement.value);
console.log(ref2.value === replacement.value);
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
1

I think this answer will guide you in the best way to handle this behavior. It's not possible to simply redirect an object to another object, but you can simply modify its values so that it matches the object you're trying to change.

You could also define a global object:

var objs = {
    1: {value: 'test'}
    2: {value: 'test2'}
};

And from there, pass around an object with the value of the key you're trying to mock. Simply change the key, and then refer to the new element.

An example:

var obj = {key: 1};
console.log(objs[obj.key]);
//Outputs: {value: 'test'}

obj.key = 2;
console.log(objs[obj.key]);
//Outputs: {value: 'test2'}
Community
  • 1
  • 1
Blue
  • 22,608
  • 7
  • 62
  • 92
  • Wouldn't having an object like `var obj1 = { realObj: { value: 'test' } }` be easier? Then you can do `var obj2 = obj1; obj2.realObj = { value: 'test2' }; console.log(obj1.realObj.value); // Outputs: test2` – iamtheib Jul 28 '16 at 20:00
0

There's no way directly to do what you want. For the very reason you've stated in your question - that's just how variables and values work in javascript.

However, your very own words in your question hints at a way to achieve something that may work. But depending on the code you're dealing with it may not be what you want.

You can simply wrap the object in another reference. So that changing the content of the reference changes the object pointed to by all variables sharing the reference. You may use either of the two reference containers available: objects or arrays:

// This works:
var obj1 = [{value:'one'}];
var obj2 = obj1;

var obj1[0] = {value:'two'};

console.log(obj1[0]); // prints {"value":"two"}
console.log(obj2[0]); // prints {"value":"two"}

Alternatively:

// This also works:
var obj1 = {obj:{value:'one'}};
var obj2 = obj1;

var obj1.obj = {value:'two'};

console.log(obj1.obj); // prints {"value":"two"}
console.log(obj2.obj); // prints {"value":"two"}
slebetman
  • 109,858
  • 19
  • 140
  • 171