FAQ: Objects - Pass By Reference

In Chapter 8 of the objects, it is mentioned that the function mutates the object, if that’s the case why did tryReassignment fail, tryReassignment is a fucntion, shouldn’t it be working.

totally lost with this example

This makes a lot of sense now, Thank you

Prolly just a typo, he meant referencing

So, like a lot of people I got confused on this particular lesson and I was hoping somebody could let me know if my logic is sound.

First, do arguments passed to functions create new variables? If the argument is a global variable I guess not since the variable exists, but what about other data types? I get that since function are local any new created variables are local as well.

Now, the way I see it, since objects are passed by reference the obj assignment in
tryReassignment() function is creating a new variable and assigning a new object. So we have a local spaceship variable and a global spaceship variable object. The console log prints the local one and the global one is unaffected since the function does not even know it exists because it was passed a reference to the object and not the variable.

Do I have my logic correct?

Not as part of the operation, no. The author creates the variable(s) the parameter(s) which will be the local reference(s) to the argument(s) passed in the function call.

If the argument is a global variable and does NOT refer to an object, array or function, then the local variable mirrors the global value (makes a copy). Any changes made to the local variable will not affect the global. When the argument is a global variable that does reference an object, array or function then only the reference is handed in so the function can still access the object. Any changes made will affect the global.

const foo = function (x) {
    x += 10
    console.log(x)
    return x
}

let x = 10
let y = foo (x)
console.log(y)    //  20
console.log(x)    //  10

In the above example, the two x’s are unique and independent. The local one does shadow the global since they have the same name.

In both cases, global and local, a separate address is allocated to each variable that points to the value in the heap, directly.

address  =>  10 is stored there
variable =>  address

With objects and arrays we cannot refer directly the stored value by address, but must refer to the reference object which contains references to the values.

address         =>  location of reference object stored in heap
location        =>  heap pointers at each index
variable[index] =>  address of value

Because of this arrangement, no values are passed into a function, only the reference to the object that points to them. The object stays in calling scope and does not get moved around or copied.

Even when we shadow the variable, the function still ‘sees’ the global.

const bar = function (a) {
    a.push (a.slice(-1)[0] + 2)
}
a = [2, 4, 6, 8]
bar(a)
console.log(a)    //  [2, 4, 6, 8, 10]
1 Like

Thanks that makes more sense.

1 Like

I was having difficulties understanding the pass by reference thing but I found this video on YT and it helped out a lot, so I’m leaving it here in the comments in case anybody else feels lost like I was.
https://www.youtube.com/watch?v=-hBJz2PPIVE

2 Likes

This helped me sooo much, thanks for sharing :smiley:

I am also very confused with this.

So you cant reassign the spaceship object with a function, but you can reassign it as follows:
spaceship = {
identified : false,
‘transport type’: ‘flying’
};

" when we pass a variable assigned to an object into a function as an argument, the computer interprets the parameter name as pointing to the space in memory holding that object. As a result, functions which change object properties actually mutate the object permanently"

In the below example, the parameter name obj was pointing to the location in memory and permanently changed the colour of the spaceship object

let paintIt = obj => {
obj.color = ‘glorious gold’
};

when they tried to reassign it, this was the explanation:

When we passed spaceship into that function, obj became a reference to the memory location of the spaceship object, (is this not he same as the first example? i dont understand why they havent worked the same way? Is it just a rule, that we cannot reassign objects inside of a function, even if they are defined with let?

Let’s put aside functions altogether for the time being and just see what happens when we are dealing with mutable values (such as arrays and objects) in general.

Suppose we assign an array or object to a variable,

let x = [1, 2, 3, 4, 5];

The array [1, 2, 3, 4, 5] is stored in some specific memory location. When we execute the above assignment statement, we are actually assigning the address/reference to that memory location to the variable x (This detail will be important to remember when we discuss multiple variables pointing to the same array or object).

Consider the following example,

let x = [1, 2, 3, 4, 5];
let y = x;      // x and y point to same array
y[2] = 99;    // We modify the array
console.log(x);  // Output: [1, 2, 99, 4, 5]
console.log(y); // Output: [1, 2, 99, 4, 5]

In the above snippet, mutation is taking place. The array [1, 2, 3, 4, 5] is mutable and is stored at some specific memory location. The variable x holds a reference to that memory location. When we execute the statement     let y = x    , we are actually assigning that same reference to the variable y as well. Now, both x and y point to the same memory address i.e. they point to the same array. We haven’t created a new instance or duplicate or copy of the array. The only thing that ties x and y together is that they are pointing to the same memory location. Other than that connection, x and y are not aware of each other and don’t keep track of each other.
When we execute the statement     y[2] = 99    , the array that is stored at the memory address that is being pointed to by y is mutated. But that array is the very same array that x is also pointing towards. Unsurprisingly, the console statements reveal that even though we explicitly mutated y, the change is also registered by x because both the variables point to the same memory location i.e. to the same array.

Now consider the situation,

let x = [1, 2, 3, 4, 5];
let y = x;      // x and y point to same array
y = [1, 2, 99, 4, 5];    // We aren't modifying the original array.
                        // We are creating a new array and assigning it to y.
console.log(x);  // Output: [1, 2, 3, 4, 5]   // x still points to original
console.log(y); // Output: [1, 2, 99, 4, 5] // y points to new array

Up to the statement     let y = x    , the situation is the same as before. Both x and y point to the same array i.e. the same memory location.
But, when we execute the re-assignment statement    y = [1, 2, 99, 4, 5];    , we sever the tenuous commonality between x and y. In the re-assignment statement, we have created a fresh array [1, 2, 99, 4, 5]. This array is stored at a different location in memory. Now, the variable y holds a reference to this new memory location. But x still holds the reference to the original memory location. x is not linked or connected or keeping track of y, therefore x is not going to update automatically. Before the mutations were registering to both variables because they were both pointing to the same memory address. But, now the pseudo connection between the two variables is broken.

With the above in mind, let’s revisit the exercise.

const spaceship = {
  homePlanet : 'Earth',
  color : 'silver'
};
 
let paintIt = obj => {
  obj.color = 'glorious gold'
};
 
paintIt(spaceship);
 
spaceship.color // Returns 'glorious gold'

The object { homePlanet : 'Earth', color : 'silver' } is stored at some memory location.
The variable spaceship holds a reference to that memory location.
When we make the function call paintIt(spaceship), the object or a copy of the object is NOT passed as the argument to the parameter obj. Instead, the reference (to the memory location) is passed as the argument and assigned to the parameter obj. When we do the mutation obj.color = 'glorious gold', we are mutating the same exact object that spaceship is pointing toward. So, the mutation can be seen outside the function.

In the second snippet

let spaceship = {
  homePlanet : 'Earth',
  color : 'red'
};

let tryReassignment = obj => {
  obj = {
    identified : false, 
    'transport type' : 'flying'
  }
  console.log(obj) // Prints {'identified': false, 'transport type': 'flying'}
};

tryReassignment(spaceship) // The attempt at reassignment does not work.
spaceship // Still returns {homePlanet : 'Earth', color : 'red'};

when we make the function call tryReassignment(spaceship), the exact situation as before happens. The variable spaceship holds a reference to a memory location (at which the object is stored). After the function call, the same reference is assigned to the parameter obj. Now (same as before), both spaceship and obj point to the same memory location and therefore the same object in memory. However, when we re-assign a new object to obj, then the pseudo connection between the spaceship and obj variables is broken. spaceship still points to the original object, but obj now holds the reference to an entirely different object. We haven’t mutated the original object. We have created a new object and assigned it to obj. The spaceship variable doesn’t care about obj. It never cared about obj even in the earlier situation. The only reason mutations to obj were being registered by spaceship earlier was because both the variables were pointing to the same memory location. A re-assignment statement is not a mutation. It is the assignment of an entirely different object to some variable.

Sometimes, we want our functions to mutate arrays and objects. In such situations, the first snippet is perfectly fine. But sometimes, we don’t want our functions to modify/mutate the original arrays/objects. In such situations, we make a copy of the array/object (either before the function call or inside the function) so that the function’s parameter holds a reference to a different memory location i.e. to an entirely different array/object in memory and consequently avoid the inadvertent mutation of the original data.

// EXAMPLE 1:
let x = [1, 2, 3, 4, 5];
let y = x;      
// x and y point to same array and mutations made via one variable
// will be seen by the other variable as well.

// EXAMPLE 2:
let x = [1, 2, 3, 4, 5];
let y = [1, 2, 3, 4, 5];
// Even though the arrays appear identical, the arrays are
// stored in different memory locations. Changes to one 
// have absolutely no effect on the other.
y[2] = 99;
console.log(x);  // Output: [1, 2, 3, 4, 5]  
console.log(y); // Output: [1, 2, 99, 4, 5] 

Because they are one and the same.

How do i know when to use bracket or dot notation?

Use bracket notation when,

  • the key is a variable
  • the key contains whitespace
  • the key may not be defined

Use dot notation when,

  • the key (property name) is known to be present
  • the key (property name) does not include whitespace
2 Likes