Let's say you want to compare two javascript objects or arrays for reference equality.
The most obvious solution would be
if (a === b) { /*...*/ };
The problem with this is that a
and b
would have to hold the references to actual objects. This can be a problem in same cases. For example, trying to hold actual references in a memoization function would create a memory leak.
One approach is to use JSON.stringify(a)
to obtain string representations of objects and compare that. But that can be prohibitively expensive in some use cases. Not to mention that actual reference equality isn't taken into consideration.
That got me wondering. Is there a way to stringify an actual reference instead of the object contents? Obviously, you can't manipulate pointers in javascript, but what if you could get just a pointer representation of some kind. A hash sum? Raw memory location? Guid or integer representation?
I know there are some kinds of object id-s when analyzing memory dump in chrome dev tools. Maybe these things can be accessed during runtime? Using some kind of special switch in node.js?
Can anyone think of a way to get this done in javascript?
If you want to use this for memorization (caching), you should use the ES6 WeakMap
. It works from Firefox 6, Chrome 36 and IE 11 on.
The WeakMap object is a collection of key/value pairs in which the keys are objects and the values can be arbitrary values. [...] The experienced JavaScript programmer will notice that this API could be implemented in JavaScript with two arrays (one for keys, one for values) shared by the four API methods. Such an implementation would have two main inconveniences. The first one is an O(n) search (n being the number of keys in the map). The second one is a memory leak issue.
It works like a map in Java - you can use arbitrary objects as keys and as values. But the keys won't prevent garbage collection, so you don't have to worry about memory leaks, but still can find the memorized calculation for a given object.
Inspired by @user2864740's remark (dude, set up a name, seriously :-)).
it could also be simply a required method on the objects that will participate in this system
This implementation extends Object prototype to include a utility to generate unique UUID for each object. generateId
implementation is taken from here.
Seems to be working for objects and arrays.
Object.prototype._id = function () {
return this.__id || (this.__id = generateId());
function generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
}
function assert(message, test) {
if (!test) {
throw new Error("ASSERTION FAILED: " + message);
} else {
console.log("PASSED: " + message);
}
}
var x = { name: "same" },
y = { name: "same" },
z = [],
x2 = x;
assert("Id is unchanging", x._id() === x._id());
assert("Id is different for different objects", x._id() !== y._id());
assert("Arrays have id too", z._id() === z._id());
assert("Id is same for same objects", x._id() === x2._id());
I'm leaving this here to see if there are problems or if maybe someone has a better idea.