Reputation: 2405
I'm learning about prototypal inheritance and I've read numerous articles and watched multiple videos on the subject. It's starting to make sense now.
The following code example, which can be found at this JSFiddle, takes an array of objects and for each object, it sets a key in a Map object, with an object as its value.
The value object has two methods, get
and set
, which get and set values to another map object from the local scope of the template
factory that returns the object.
My understanding is if we used this example to hypothetically generate 100k objects in the databaseMap
, each object would have its own set
and get
methods, using unnecessary amounts of memory? My understanding is this is where I should be using prototypal inheritance?
So my question is, how do I move the set
and get
methods to say the scope of the init
function and set them to the prototype of the object returned from template
, so that when called, they set and get on the storeMap
Map, from within the scope of the template
function that generated the object?
Or, am I not understanding this correctly?
const config = [
{
id: 'obj1',
value: 'value1',
},
{
id: 'obj2',
value: 'value2',
},
{
id: 'obj3',
value: 'value3',
},
{
id: 'obj4',
value: 'value4',
},
]
function init() {
const databaseMap = new Map()
function template(storeConfig) {
const { id } = storeConfig
const storeMap = new Map()
return {
id,
set(key, value) {
console.log(`Setting data to store ${id}.`)
// Do future work here
return storeMap.set(key, value)
},
get(key) {
// Do future work here
return storeMap.get(key)
},
}
}
config.forEach(x => {
const store = template({ id: x.id })
databaseMap.set(x.id, store)
})
return databaseMap
}
const db = init()
const getStore = db.get('obj4')
getStore.set('testing1', 'testing1')
console.log('GET STORE')
console.log(getStore)
console.log('GET TESTING 1')
console.log(getStore.get('testing1'))
Upvotes: 2
Views: 55
Reputation: 92440
Have you considered just using a single object with get
and set
defined on it? Instead of creating a new object your can create a new Template()
that — then you can take advantage of the way this
works in javascript to allow it to work for all instances while avoiding having to capture a new closure for each function.
For example:
const config = [{id: 'obj1', value: 'value1'}, {id: 'obj2', value: 'value2'},{id: 'obj3',value: 'value3',},{id: 'obj4',value: 'value4',}]
function init() {
const databaseMap = new Map()
// a single proto object
const protoObj = {
set(key, value) {
console.log(`Setting data to store ${this.id}.`)
// Do future work here
return this.storeMap.set(key, value)
},
get(key) {
return this.storeMap.get(key)
}
}
function Template(storeConfig) {
this.id = storeConfig.id
this.storeMap = new Map()
}
// use the object for the prototype
Template.prototype = protoObj
config.forEach(x => {
const store = new Template({ id: x.id })
databaseMap.set(x.id, store)
})
return databaseMap
}
const db = init()
const getStore = db.get('obj4')
getStore.set('aTest', 'testing1')
console.log('GET STORE')
console.log(getStore)
console.log('GET aTest')
console.log(getStore.get('aTest'))
Of course you can also define the function directly on the prototype:
Template.prototype.set = function (key, value) {
return this.storeMap.set(key, value)
}
Template.prototype.get = function (key, value) {
return this.storeMap.get(key, value)
}
EDIT based on comment
You can define the functions on their own in such a way that they use this
to access the object's properties. Then you can just add a reference from them to the object. Like:
const config = [{id: 'obj1', value: 'value1'}, {id: 'obj2', value: 'value2'},{id: 'obj3',value: 'value3',},{id: 'obj4',value: 'value4',}]
function init() {
const databaseMap = new Map()
function set(key, value) {
console.log(`Setting data to store ${this.id}.`)
// Do future work here
return this.storeMap.set(key, value)
}
function get(key) {
// Do future work here
return this.storeMap.get(key)
}
function template(storeConfig) {
return {
id: storeConfig.id,
storeMap:new Map(),
set:set,
get:get
}
}
config.forEach(x => {
const store = template({ id: x.id })
databaseMap.set(x.id, store)
})
return databaseMap
}
const db = init()
const getStore = db.get('obj4')
getStore.set('TestKey', 'testing1')
console.log('GET STORE')
console.log(getStore)
console.log('TestKey')
console.log(getStore.get('TestKey'))
ALTERNATIVE
const config = [{id: 'obj1', value: 'value1'}, {id: 'obj2', value: 'value2'},{id: 'obj3',value: 'value3',},{id: 'obj4',value: 'value4',}]
function init() {
const databaseMap = new Map()
// a single proto object
const protoObj = {
set(key, value) {
console.log(`Setting data to store ${this.id}.`)
// Do future work here
return this.storeMap.set(key, value)
},
get(key) {
return this.storeMap.get(key)
}
}
function template(storeConfig) {
const id = storeConfig.id
const storeMap = new Map()
return Object.assign(Object.create(protoObj), { id, storeMap })
}
config.forEach(x => {
const store = template({ id: x.id })
databaseMap.set(x.id, store)
})
return databaseMap
}
const db = init()
const getStore = db.get('obj4')
getStore.set('aTest', 'testing1')
console.log('GET STORE')
console.log(getStore)
console.log("PROTOTYPE OF getStore")
console.log(Object.getPrototypeOf(getStore))
console.log('GET aTest')
console.log(getStore.get('aTest'))
Upvotes: 1