1

I ran into an issue when I expect a member in a returned object to have the correct value of a variable defined in the parent scope. However, the value of this member never changes and I had to make a getter method to retrieve the correct value. For a trivial example, below is a subset of an Adjacency Matrix representation of a graph:

function AdjacencyMatrix() {
 // Here is the set of Vertices
 var V = [1, 2, 3];
 // Here's some functionality that will remove a vertex at some point,
 // right now we're just concerned with updating what V is equal to
 function removeVertex(v) {
 V.push(4);
 V = [];
 console.log(V);
 }
 // A "getter" method for the list of vertices
 function getVertices() {
 return V; 
 }
 // Ran when the Adjacency Matrix is initialized
 console.log(V);
 return Object.freeze({
 // Member that holds a reference to V
 vertices: V,
 // Methods that will be used later
 removeVertex: removeVertex,
 getVertices: getVertices
 });
}
// Initially logs [1, 2, 3], which is expected
var M = AdjacencyMatrix();
// Logs [], which is expected
M.removeVertex();
// Logs [1, 2, 3, 4], which is unexpected.
// Instead, it should log []
console.log(M.vertices);
// Logs [], which is expected
console.log(M.getVertices());

Shouldn't the vertices member in the returned object always maintain a reference to what the variable V points to? Instead, in this example, accessing the vertices member on M maintains a reference to the array initially assigned to the variable V and ignores any reassignment of variable V.

Or, when assigning the vertices member to V, does it hold a reference to the value of V instead of whatever value the variable has?

Sorry if the wording of this problem is difficult to understand, I tried my best to state my expectations and results.

JLRishe
102k19 gold badges139 silver badges171 bronze badges
asked Dec 23, 2014 at 19:47

3 Answers 3

2

vertices: V, means:

put a reference to what V refers to to the vertices property.

That's it - it's not a closure, it's just an assignment.

So as soon as you reassign V to refer to something else - the vertices attribute does not reflect that, since it stores an original reference.

answered Dec 23, 2014 at 19:53
Sign up to request clarification or add additional context in comments.

Comments

1

M.vertices does not involve a closure.

In an object literal, the right hand side of each key/value pair is evaluated, and the result of that evaluation is what is assigned to each the object's properties.

When this executes:

return Object.freeze({
 // Member that holds a reference to V
 vertices: V,
 // Methods that will be used later
 removeVertex: removeVertex,
 getVertices: getVertices
});

V is evaluated to the array that V is referencing at that moment. So the produced object references that array, but it has no connection to V.


To get the behavior you are describing (if that is what you indeed want). You could define a getter and setter for vertices that do use a closure:

var o = {
 // Methods that will be used later
 removeVertex: removeVertex,
 getVertices: getVertices
}
Object.defineProperty(o, 'vertices', {
 get: function () { return V; },
 set: function (val) { V = val; } // or you can omit the setter
 // to make the property readonly
}); 
return Object.freeze(o);
answered Dec 23, 2014 at 19:57

3 Comments

I love this explanation! I do have one question though, why does the value of M.vertices get updated to [1, 2, 3, 4] instead of staying at [1, 2, 3]? In the removeVertex method, I'm pushing the value 4 onto M and this change is reflected when I access M.vertices.
Because you're still holding a reference, so you can mutate the referred object and observe mutations.
@JoshBlack It's what zerkms said. Evaluating the expression V does not create a brand new array. It produces a reference to the array that V is referencing at that time. If that array is modified afterward, then it will be reflected when you access it via M.vertices.
0

Vertices holds the value of V that was originally assigned to it. If you come from an object oriented language background like C#, this is equivalent to "pass by value" (i.e only the value gets passed and not the reference).

answered Dec 23, 2014 at 20:01

8 Comments

Why is it not true ? Although is not technically "pass by value", conceptually it is easier to understand it this way. The 'value' of V is assigned to Vertices and not its reference.
It's not "pass by value" in any way. Like at all. It has a special name "call by sharing". "The 'value' of V is assigned to Vertices and not its reference." --- this is simply wrong, since it's exactly the opposite: it's the reference that is assigned.
I still don't get it. If it is the reference that is assigned to Vertices, then why doesn't it get updated when V changes ?
Does M.removeVertex(); not mutate it ?
If it was mutated by M.removeVertex(); then console.log(M.vertices); should have logged [] instead of [1,2,3,4]
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.