Hey everyone,
I am building a library for Graph Object Notation, at the moment in super early stage, and I came across a really nice "loophole" to what I imagined being the biggest obstacle of the project : Getting the memory address of the objects in JavaScript. Here is a nice post if you need a quick reminder on how memory works in JavaScript!
As you may know, you can't access them for security reasons, end of the post, thank you for reading...
...but turns out, you can cheat a little bit there. The actual address isn't really that important in my case, what's important is the consistency of the "fake address" that we will generate and make sure the same object always spits out the same address!
First though is to go on and brute force things, building an array of known Object, another of fake address and comparing every object against that array. Turns out it works, but here comes the slow library judgement.
Second though, building hashes of the object based on properties and values, then only comparing with "same hash" object, works as well, but not really efficient either.
Then came an idea.
The Map object isn't really used in the JavaScript front-end world, but it's really effective at finding if it has a key defined, and it can hold any type of data as a key. This is contrary to the Object object, where keys can only be strings.
1 + 1 = success, let's use the objects themselves as key, and the fake address as value.
Here is a short video on how it works : https://youtu.be/-ZenKpRfJdo
And the next one in a more functional programming style, with a nice triple arrow function : https://youtu.be/r7y8roTIPig
And for those not wanting to watch a video, here's the code :
(the live version is here)[https://gon.arthurj.now.sh/references]
https://codesandbox.io/s/vibrant-northcutt-wkh2e
const user1 = { name: "arthur" };
const users = [user1, { name: "arthur" }, { name: "Joe" }, user1];
//This generator doesn't garantee uniqueness, but looks way more memoryish than a incremental counter
//if you use this code for real, do incremental or something else unique!
function* generator() {
while (true) {
const random = Math.random()
.toString(16)
.slice(2, 10);
yield `0x${random}`;
}
}
const preload = (knowObjects, refs, generate) => (reference = false) => {
if (reference) {
return refs;
} else {
return object => {
let address;
if (knowObjects.has(object)) {
address = knowObjects.get(object);
} else {
address = generate.next().value;
knowObjects.set(object, address);
refs[address] = object;
}
return address;
};
}
};
const setup = preload(new Map(), {}, generator());
const findRef = setup(false);
const array = users.map(u => findRef(u));
/*
console.log something like that, and builds up the knowObjects map / refs object
[
"0xf094c649",
"0x7de35306",
"0x6a99aa2f",
"0xf094c649"
]
*/
const refs = setup(true);
/*
console.log something like this
{
"0xf094c649": {
"name": "arthur"
},
"0x7de35306": {
"name": "arthur"
},
"0x6a99aa2f": {
"name": "Joe"
}
}
*/
Top comments (3)
This article is totaly wrong since the beginning. There's no such a "primitive type" (only primitive values, see ) or copying primitive values to a newly assigned "variable" (i.e. identificator since it only points to the data structure) as described in the article:
Just remember, ALL data is passing by and assinged by a reference in JavaScript
Speaking about objects addresses, just run the node js with the flag --allow-natives-syntax and do the following.
Code:
var obj = { name: 'some name' };
Then execute:
%DebugPrint(obj)
And now you see the detailed debug print of the object inside the node, specfically the first lines define the memory addresses where the object identificator
obj
and assigned to it data structure are located.Thank you for this article. You said that we cannot access addresses due to security reasons. Can you share some more information on that? Maybe you could share some article that talks more about it? Thanks!
I never ever thought I'd need to retrieve a Javascript function based on its pointer, but damn today I did. Thanks for your article!