Last active
June 7, 2023 16:17
-
-
Save AloofBuddha/92ee6749a8be48c984881a4523f533c3 to your computer and use it in GitHub Desktop.
Pass by value vs reference in JS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// primitives are 'passed by value' in JS | |
// meaning the value of the variable is copied over into a new local variable in the function | |
let n = 1; | |
function addOne(x) { | |
x += 1; | |
return x; | |
} | |
let result = addOne(n); | |
console.log(n); // 1 | |
console.log(result); // 2 | |
/* | |
Breakdown: | |
n = 1 at the global level | |
addOne(n) is called, argument is evaluated to its actual value 1 | |
internally in the addOne function, x is set to 1 | |
we add 1 to the value of x itself and then return it, making the updated value available to the calling site | |
where we then store it in result | |
by printing both we can confirm the original input value of n is unchanged | |
*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// let's now consider some caveats to the above idea | |
let n = 1; | |
function addOne(x) { | |
x += 1; | |
} | |
let result = addOne(n); | |
console.log(result); // undefined | |
console.log(n); // 1 | |
/* | |
Breakdown: | |
Nothing changed. Why? | |
addOne(n) is called, argument is evaluated to its actual value 1 | |
internally in the addOne function, x is set to 1 | |
we add 1 to the value of x itself but never return it | |
x equals 2 before the function ends, but once the function ends this variable/value dissapears | |
if we don't return anything we return undefined by default and as expected the original value is unaffected | |
*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// complex types are 'pass by reference' in JS | |
// meaning the *memory address* of the variable is copied over into a new local variable in the function | |
// meaning the internal function variable refers to the same exact thing (not a copy) as the original argument | |
let point = { x: 1, y: 2 }; | |
function addOneToPoint(myPoint) { | |
myPoint.x += 1; | |
myPoint.y += 1; | |
} | |
addOneToPoint(point); | |
console.log(point); // { x: 2, y: 3 } | |
/* | |
Breakdown: | |
point is set to the object { x: 1, y: 2 } at the global level. Let's just say this lives at the memory address 42. | |
addOneToPoint(point) is called, argument is converted to it's memory address (42) | |
internally in the addOneToPoint function, myPoint is set to the object at memory address 42, so it 'references' the exact same object | |
as what was passed in as an argument | |
we access the x and y keys of myPoint and update them, then end the function (no return) | |
note that at the call site we don't set it to a new variable because it's unnecessary, the function itself mutated the passed in argument | |
by printing it we can confirm that passed in argument was mutated | |
*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// some caveats for pass by reference | |
let point = { x: 1, y: 2 }; | |
function alterPoint(myPoint) { | |
myPoint = { a: 1000, b: 2000 } | |
} | |
alterPoint(point); | |
console.log(point); // { x: 1, y: 2 } | |
/* | |
Note this didn't work, we didnt alter what point references. Why? | |
Breakdown: | |
point is set to the object { x: 1, y: 2 } at the global level. Let's just say this lives at the memory address 42. | |
alterPoint(point) is called, argument is converted to it's memory address (42) | |
internally in the alterPoint function, myPoint is set to the object at memory address 42, so it 'references' the exact same object | |
as what was passed in as an argument | |
myPoint is then set to a brand new object ( { a: 1000, b: 2000 } ) which lives at a totally different memory address (say 84) | |
we then end the function without returning anything. the variable myPoint is destroyed at the end of the function, | |
so what it was referencing (memory address 84) is also lost | |
by printing point we can confirm that passed in argument was unchanged | |
Just because we pass in the original by reference doesn't mean the interal variable can't be made to reference something new | |
and if that is done no changes will propagate to the original. | |
*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// a caveat for pass-by-anything | |
let x = 1; | |
function addOne(x) { | |
x += 1; | |
return x; | |
} | |
let result = addOne(x); | |
console.log(x); // 1 | |
console.log(result); // 2 | |
/* | |
Just wanted to demonstrate 'varaible shadowing' here. the variable 'x' and the addOne parameter 'x' appear the same, but JS | |
is smart enough to keep them from conflicting | |
changing the internal addOne version of x has no effect on the global x | |
Shadowing does not effect anything with the same name outside of it's scope, but it will prevent you from referencing the global x | |
Just know this is normal practice, don't worry about using a function parameter name that is identical to the argument it is passing | |
in, there's no actual problem there. | |
*/ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment