Allasso Allasso - 4 months ago 12
Javascript Question

Coerce an object living in memory to point to a different object?

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.

Answer

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);