Getting the memory addresses of objects
in JavaScript, kind of
Arthur Juchereau
Creator / Maintainer of Graph Object Notation
Founder of MakeItHappen.dev
intermittent on youtube/twitch
freelancer / contractor
full stack dev
Why would I want to know the memory address of an object?
Great way to talk about
Generators, Maps and Currying
But first, memory in JS
- Primitives
- Objects
You only need to know two concepts
Primitives
undefined
booleans
numbers
bigInt
strings
symbols
null
They are accessed by value (AKA immutable)
console.log(typeof notdefined)
// undefined
console.log(typeof true)
// boolean
console.log(typeof 42)
// number
console.log(typeof 42n)
// bigint
console.log(typeof "Hello")
// string
console.log(typeof Symbol('gon'))
// symbol
console.log(typeof null)
// object
address | value |
---|---|
0x001 | true |
0x002 | 42 |
0x003 | 42n |
0x004 | "Hello" |
0x005 | Symbol('gon') |
0x006 | null |

In JavaScript, typeof null is 'object', which incorrectly suggests that null is an object (it isn’t, it’s a primitive)
This is a bug and one that unfortunately can’t be fixed, because it would break existing code.
2ality.com if interested
Objects
Objects
Array
Dates
Maps
Sets
....
Basically the rests (except maybe functions),
accessed by reference (AKA mutable)
console.log(typeof {foo:"bar"})
// object
console.log(typeof ["bar"])
// object
console.log(typeof new Date())
// object
console.log(typeof new Map())
// object
console.log(typeof new Set())
// object
console.log(typeof (()=>('hello')))
// function
Address | value |
---|---|
0x001 | <0xa01> |
0x002 | <0xa02> |
... | ... |
0xa01 | {foo:"bar"} |
0xa02 | ["bar"] |
... | ... |
What does it mean?
const myString = "foo"
let copy = myString
copy = "bar"
console.log("myString", myString)
console.log("copy", copy)
primitives
What does it mean?
const myString = "foo"
let copy = myString
copy = "bar"
console.log("myString", myString)
console.log("copy", copy)
myString foo
copy bar
primitives
What does it mean?
const myObject = {foo:"bar"}
let copy = myObject
copy.foo = "mutable"
console.log("myObject", myObject)
console.log("copy", copy)
objects
What does it mean?
const myObject = {foo:"bar"}
let copy = myObject
copy.foo = "mutable"
console.log("myObject", myObject)
console.log("copy", copy)
myObject > Object { foo : "mutable" }
copy > Object { foo : "mutable }
objects
Why is that?
const myObject = {foo:"bar"}
let copy = myObject
copy.foo = "mutable"
console.log("myObject", myObject)
console.log("copy", copy)
objects
const myString = "foo"
let copy = myString
copy = "bar"
console.log("myString", myString)
console.log("copy", copy)
primitives
myObject > Object { foo : "mutable" }
copy > Object { foo : "mutable }
myString foo
copy bar
Why is that?
const myObject = {foo:"bar"}
let copy = myObject
copy.foo = "mutable"
console.log("myObject", myObject)
console.log("copy", copy)
objects
const myString = "foo"
let copy = myString
copy = "bar"
console.log("myString", myString)
console.log("copy", copy)
primitives
name | address | value |
---|---|---|
myString | 0x001 | foo |
name | address | value |
---|---|---|
myObject | 0x001 | <0xa01> |
... | ... | ... |
0xa01 | {foo:"bar"} | |
Why is that?
const myObject = {foo:"bar"}
let copy = myObject
copy.foo = "mutable"
console.log("myObject", myObject)
console.log("copy", copy)
objects
const myString = "foo"
let copy = myString
copy = "bar"
console.log("myString", myString)
console.log("copy", copy)
primitives
name | address | value |
---|---|---|
myString | 0x001 | foo |
copy | 0x002 | foo |
name | address | value |
---|---|---|
myObject | 0x001 | <0xa01> |
copy | 0x002 | <0xa01> |
... | ... | ... |
0xa01 | {foo:"bar"} |
Why is that?
const myObject = {foo:"bar"}
let copy = myObject
copy.foo = "mutable"
console.log("myObject", myObject)
console.log("copy", copy)
objects
const myString = "foo"
let copy = myString
copy = "bar"
console.log("myString", myString)
console.log("copy", copy)
primitives
name | address | value |
---|---|---|
myString | 0x001 | foo |
copy | 0x002 | bar |
name | address | value |
---|---|---|
myObject | 0x001 | <0xa01> |
copy | 0x002 | <0xa01> |
... | ... | ... |
0xa01 | {foo:"mutable"} |

buzzwords for technical interviews
Memory addresses
(in green)
name | address | value |
---|---|---|
myObject | 0x001 | <0xa01> |
copy | 0x002 | <0xa01> |
... | ... | ... |
0xa01 | {foo:"mutable"} |
What we'll need
- Map object
- double arrow functions ("impure" currying)
- Generator
Map object
- Collection of key / value pairs
- Keys can be anything
- Iterable
- key ordering
- usually benchmark better for large collection
Map object
const knownObjects = new Map()
const me = {name:"Arthur"}
knownObjects.set(1,me)
knownObjects.set(me,1)
typeof knownObjects.get(1) // object
typeof knownObjects.get(me) // number
knownObjects.size // 2 <= VERY fast
knownObjects.has(1) // true <= VERY fast
for(let [key,value] of knownObjects){
console.log("key: ",key," / value ",value)
}
// key: 1 / value Object { name: "Arthur" }
// key: Object { name: "Arthur" } / value 1
Currying
(double arrow function)
const add = x => y => (x + y)
const addFive = add(5)
const addThree = add(3)
console.log(addFive(5)) //10
console.log(addThree(5)) //8
Currying
(double arrow function)
const compose = x => y => x + " " + y
const greet = compose('hello')
const politeToMaster = compose(greet('Arthur,'))
const sooialize = politeToMaster("How are you doing today?")
console.log(socialize)
hello Arthur, How are you doing today?
function compose (x){
return y => x + " " + y
}
console.log(
compose(
compose('hello')('Arthur,')
)
("How are you doing today?")
)
impure Currying
(double arrow function)
const setup = (generator) => {
const knownObjects = new Map()
const generate = generator()
return [
(object) => {
//You're getting the address of an object
...
},
() => {
//Dump References
...
}
]
}
Generators
- Can "pause" midway
- Can resume
- is an iterator (each step has a value and a "doneness")
- May never end

Generators
let generator = function* (){
yield 'this'
yield 'is'
yield 'iterable'
return 'finished'
}
let generate = generator()
console.log(generate.next())
// Object { value: "this", done: false }
console.log(generate.next())
// Object { value: "is", done: false }
console.log(generate.next())
// Object { value: "iterable", done: false }
console.log(generate.next())
// Object { value: 'finished', done: true }
console.log(generate.next())
// Object { value: undefined, done: true }
Generators
let generator = function* (){
let inject
inject = yield 'this' + " " + inject
inject = yield 'is' + " " + inject
inject = yield 'iterable' + " " + inject
return 'finished' + " " + inject
}
let generate = generator()
console.log(generate.next('Hello1'))
// Object { value: "this undefined", done: false }
console.log(generate.next('Hello2'))
// Object { value: "is hello2", done: false }
console.log(generate.next('Hello3'))
// Object { value: "iterable hello3", done: false }
console.log(generate.next('Hello4'))
// Object { value: 'finished hello4', done: true }
console.log(generate.next('Hello5'))
// Object { value: undefined, done: true }
Generators
let generator = function* (start = 61440){
for(let i = start;i<Infinity;i++){
yield `0x${i.toString(16)}`
}
}
let generate = generator()
console.log(generate.next().value) // 0xf000
console.log(generate.next().value) // 0xf001
console.log(generate.next().value) // 0xf002
console.log(generate.next().value) // 0xf003
console.log(generate.next().value) // 0xf004
Let's put it all together
const [findRef,dumpRefs] = setup()
const me = {name:'Arthur'}
const people = [
me,
{name:'Bob'},
{name:'Christine'},
{name:'Arthur'}
me
]
const stack = {
people:people.map(findRef),
heap:dumpRefs()
}
console.log(stack)
const setup = (target='heap.') => {
const generator = function* (start = 0){
for(let i = start;i<Infinity;i++){
yield `0x${i.toString(16)}`
}
}
const generate = generator(61440)
const knownObjects = new Map()
return [
// FindRef(object)
(object) => {
let address
if(knownObjects.has(object)){
address = knownObjects.get(object)
}
else{
//Add to knowObjects + generate address
address = generate.next().value
knownObjects.set(object,address)
}
return `ref:${target}${address}`
},
// dumpRef()
() => {
const heap = {}
for(let [o,a] of knownObjects){
heap[a] = o
}
return heap
}
]
}
const [findRef,dumpRefs] = setup()
const me = {name:'Arthur'}
const people = [
me,
{name:'Bob'},
{name:'Christine'},
{name:'Arthur'}
me
]
const stack = {
people:people.map(findRef),
heap:dumpRefs()
}
console.log(stack)
const setup = (target='heap.') => {
const generator = function* (start = 0){
for(let i = start;i<Infinity;i++){
yield `0x${i.toString(16)}`
}
}
const generate = generator(61440)
const knownObjects = new Map()
return [
(object) => {
let address
if(knownObjects.has(object)){
address = knownObjects.get(object)
}
else{
//Add to knowObjects
//generate address
address = generate.next().value
knownObjects.set(object,address)
}
return `ref:${target}${address}`
},
() => {
const heap = {}
for(let [o,a] of knownObjects){
heap[a] = o
}
return heap
}
]
}
heap: {…}
0xf000: Object { name: "Arthur" }
0xf001: Object { name: "Bob" }
0xf002: Object { name: "Christine" }
0xf003: Object { name: "Arthur" }
people: (5) […]
0: "ref:heap.0xf000"
1: "ref:heap.0xf001"
2: "ref:heap.0xf002"
3: "ref:heap.0xf003"
4: "ref:heap.0xf000"
Why is it useful?
Graphs !
Thanks for listening
Arthur Juchereau
Twitter/@ArthurBienSur
Twitch/ArthurBienSur
YouTube/Arthur BienSur
Memory addresses
By pookmook
Memory addresses
- 172