1

The MDN document on the JavaScript Map Object provides useful information but seems to leave out a few important points. Perhaps they are obvious to most but it's not clear to me why it works the way it does and I would appreciate clarification please.

It appears that the keys, when not strings, are references to objects including function objects. And, apart from function objects, it appears that the values of objects are references to the objects also. Thus, in the code below, mapF.get(updateFunc).b = 25 updates the object held in the map, as opposed to the mapF.get() returning a copy of the object only.

But the same doesn't appear to hold for the case when the value is a function object, but appears to make a copy of the function, such that after the function funcInMap is updated, the mapF.get('funcInMap')(4) returns 8 instead of 12; and therefore appears to be holdiong a copy of the original definition of funcInMap.

Am I making a mistake or is this the way it works and the way it should be expected to work? Thank you.

var funcInMap = function (x) {
 return x * 2;
};
function updateFunc() {
  funcInMap = function (x) { return x * 3; };
}
var mapF = new Map();

mapF.set(updateFunc, {a: 5, b: 10});
mapF.set('funcInMap',funcInMap);

console.log("b pre map update: " + mapF.get(updateFunc).b); // 10
mapF.get(updateFunc).b = 25;
console.log("b post map update: " + mapF.get(updateFunc).b); // 25
console.log(mapF.get(updateFunc));
console.log("funcInMap pre update : " + mapF.get('funcInMap')(4)); // 8

updateFunc();
console.log("funcInMap post update : " + funcInMap(4)); // 12

console.log("mapF funcInMap post update : " + mapF.get('funcInMap')(4)); // 8

Added after receiving answer.

function updateFunc() { }
    
var mapF = new Map(),
    obj = {a: 5, b: 10};
mapF.set(updateFunc, obj);
  
console.log("Original obj: " + Object.values(mapF.get(updateFunc))); 
// Return 5, 10

obj = {a: 105, b: 110};
    
console.log("Updated obj: " + Object.values(mapF.get(updateFunc))); 
// Return 5, 10
    
/*
  I would've been stupid to expect the second group to return
  105, 110; but that is what I was expecting when the objects
  were functions.
*/

After changing some of my project code to use maps instead of regular objects it occurred to me that I was being a bit stupid again in setting a map key to have a value that is an object. It would make sense perhaps in some cases; but if the objective is to relate some data to a DOM element or function in manner that is similar to adding properties to them but will never clash in the future, wouldn't the point be to add a map to a map?

So, the code example above of mapF.set(updateFunc, {a: 5, b: 10}) should be mapF.set(updateFunc, new Map( [ ['a', 5], ['b', 10] ] ) ) and properties can be added(etc.) using mapF.get(updateFunc).set('c', 20).

However, the inner map cannot be used without use get twice. Thus, it would appear that an null object would be more easily coded anyway.

function myFunc() { };

var map_map = new Map([ [myFunc, new Map([ ['a',10], ['b',20]]) ] ] );

var obj = Object.create(null, {
 a: { value: 10, enumerable: true },
 b: { value: 20, enumerable: true }
});

var map_obj = new Map([[myFunc, obj]]);

console.log( map_map.get(myFunc).get('a') ); //=> 10
console.log( map_map.get(myFunc)['a'] ); //=> undefined
console.log( map_obj.get(myFunc).a); // => 10

1
  • no it's just the same address, it has nothing to do with the Map object Commented Sep 12, 2022 at 3:18

1 Answer 1

2

when you write in JS:

var funcInMap = function (x) { return x * 2; };

the JS interpreter creates 2 things:

-1- the assembler code corresponding to function (x) { return x * 2; }
which it places at a memory address @_memoryAddress_x1

-2- create the funcInMap variable to which it attaches the memory address @_memoryAddress_x1

subsequently you coded:

mapF.set('funcInMap',funcInMap);

which the JS interpreter "transforms" to
mapF.set('funcInMap', @_memoryAddress_x1);
because @_memoryAddress_x1 matches the contents of the funcInMap variable

in updateFunc() you do a similar operation: it creates assembly code for
function (x) { return x * 3; }
to an address = @_memoryAddress_ZZ

and replace the value of funcInMap with @_memoryAddress_ZZ

but the address @_memoryAddress_x1 still exists
as well as its assembly code for execution.

IN a similar logic (no need to use Map Objects)

let
  function_A = () => 'a'
, function_B = () => 'b'
, function_C = function_A
  ;

console.log( function_A() )   // return 'a'
console.log( function_C() )   // return 'a'

function_A = function_B

console.log( function_A() )   // return 'b'
console.log( function_C() )   // return 'a'

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I was rather stupid. I added a snippet at the end with a simple object and the results are the same. I should have expected that with functions. Thank you for the explanation and example. I was thinking that the function was "changed" rather than a new one created to whcih the name now points. And the old function cannot be garbage collected as long as the Map holds a reference to it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.