I want to produce a hash derived from an Object
's reference, and then associate the hash string to the object itself into a dictionary.
I have heard of object-hash and attempted the following implementation:
const objectHash = require('object-hash');
class A {
a: string;
constructor() {
this.a = '1';
}
}
let a = new A();
let ab = new A();
console.log(objectHash(a)); // 712041d72943c4794bb23d1d455e17b3a4ea17f5
console.log(objectHash(ab));// 712041d72943c4794bb23d1d455e17b3a4ea17f5
In despite of a
and ab
being different objects (although instances of the same class), the hash produced is equal, which is not the expected result. That is because the library hashes object values rather than object reference.
Expected result
let foo = new A();
let bar = new A();
const fooH = objectHash(foo); <-- Produces a unique hash string representing the reference of "foo"
const barH = objectHash(bar); <-- Produces a unique hash string representing the reference of "bar"
let objects = {
fooH: foo,
barH: bar
}
This could probably be achieved in C or C# by using pointers and addresses, but what about Javascript? If anybody can guide me on the right path to incapsulate an object's reference into a string, it would be appreciated.
CodePudding user response:
It is not possible to get an object's reference in JavaScript in order to calculate a hash of it. The reference is an internal value for the engine that is not normally exposed.
However, if you want to index some data against an object, you can use a Map
, since the keys can be any arbitrary JavaScript value, thus allowing objects. Since objects are unique during comparison, that means that the same object returns the value:
class A {
constructor() {
this.a = '1';
}
}
const foo = new A();
const bar = new A();
const map = new Map()
.set(foo, "hello")
.set(bar, "world");
console.log(map.get(foo), map.get(bar));
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
JavaScript also has a WeakMap
- it only allows objects as keys but in turn it only holds a weak reference to them. This means that once any other reference to the key is gone, the WeakMap
will not prevent the object from being garbage collected.
Maps, and especially WeakMaps, are a viable way to extend foreign objects without actually having to nest them in your own hierarchy. Here is a quick demo
import {a, b} from 'foreign';
const extension = new WeakMap()
extension.set(a, {
myProperty1: true,
myProperty2: 40,
myProperty3: "hello",
});
extension.set(b, {
myProperty1: false,
myProperty2: 2,
myProperty3: "world"
});
Here we get some foreign objects a
, and b
we do not control and extend them with our own properties without ever needing to change or clone them. Looking the object in the WeakMap
gives the extended properties.
See a more detailed description by Benjamin Gruenbaum
For further reference a Set
and a WeakSet
exhibit the same properties as a Map and WeakMap, respectively, in terms of storing objects. However, they without an extra value for the object. That can be useful, for example, to keep track of seen objects. Which event handlers have fired, or which nodes in a graph have been visited, and similar.