Masukkan Password
58 Pass by Value & Pass by Reference
Lecture ini adalah kelanjutan langsung dari value type vs reference type. Kalau lecture sebelumnya menjawab:
βApa yang terjadi ketika kita assign primitive/object ke variabel lain?β
maka lecture ini menjawab:
βApa yang terjadi ketika primitive/object kita kirim sebagai argument ke function?β
Konsepnya sangat mirip, jadi kalau kamu sudah memahami βcopy value vs copy referenceβ, lecture ini sebenarnya cukup logis.
1. Gambaran besar: apa itu Pass by Value dan Pass by Reference?
Misalnya kita punya function:
function checkIn(flightNum, passenger) {
// ...
}
Kemudian kita punya:
let flight = "BNB 289";
let person = {
name: "John",
passport: 123456
};
Lalu function dipanggil:
checkIn(flight, person);
Ada dua hal yang dikirim:
flight
β
"BNB 289"
dan:
person
β
object { name: "John", passport: 123456 }
Karena:
"BNB 289" β String β primitive
object β Object β reference type
maka secara mental model:
flight β PASS BY VALUE
person β reference yang disalin
Namun ada catatan teknis penting yang akan kita bahas di akhir: secara spesifikasi JavaScript, argument sebenarnya selalu pass-by-value. Untuk object, value yang disalin adalah reference.
Untuk mengikuti bahasa lecture, kita tetap akan menggunakan istilah pass by value dan pass by reference, lalu kita luruskan istilahnya di bagian akhir.
2. Kita lihat contoh dari lecture
Kira-kira kodenya seperti ini:
function checkIn(flightNum, passenger) {
flightNum = "BNB 9999";
passenger.name = "Mr " + passenger.name;
if (passenger.passport === 123456) {
console.log(
`Hello ${passenger.name}, you are checked in for flight ${flightNum}`
);
}
}
let flight = "BNB 289";
let person = {
name: "John",
passport: 123456
};
checkIn(flight, person);
console.log(flight);
console.log(person);
Output-nya kira-kira:
Hello Mr John, you are checked in for flight BNB 9999
BNB 289
{
name: "Mr John",
passport: 123456
}
Nah, ini yang menarik.
Di dalam function:
flightNum = "BNB 9999";
tetapi:
console.log(flight);
tetap:
BNB 289
Sedangkan:
passenger.name = "Mr " + passenger.name;
mengubah:
person.name
menjadi:
Mr John
Kenapa yang satu tidak berubah, sedangkan yang satunya berubah?
Jawabannya: value vs reference.
3. Bagian pertama: flight
Kita punya:
let flight = "BNB 289";
flight menyimpan String.
String adalah primitive.
Secara mental model:
flight
β
"BNB 289"
Kemudian kita panggil:
checkIn(flight, person);
Saat function dipanggil:
function checkIn(flightNum, passenger)
parameter flightNum mendapatkan value dari flight.
Jadi:
flight
β
"BNB 289"
flightNum
β
"BNB 289"
Value-nya disalin.
4. Jadi ada dua value
Secara sederhana:
flight β "BNB 289"
flightNum β "BNB 289"
Keduanya memang memiliki value yang sama.
Tetapi keduanya adalah variable/binding yang berbeda.
Sekarang function melakukan:
flightNum = "BNB 9999";
Yang berubah adalah flightNum.
Sekarang:
flight
β
"BNB 289"
flightNum
β
"BNB 9999"
flight tidak ikut berubah.
5. Kenapa flight tidak ikut berubah?
Karena ketika argument primitive dikirim ke function, value-nya disalin.
Analogi paling gampang:
Bayangkan kamu punya kertas:
flight
ββββββββββββ
β BNB 289 β
ββββββββββββ
Kemudian kamu fotokopi:
flight
ββββββββββββ
β BNB 289 β
ββββββββββββ
flightNum
ββββββββββββ
β BNB 289 β
ββββββββββββ
Sekarang kamu menghapus isi kertas kedua dan menulis:
flightNum
βββββββββββββ
β BNB 9999 β
βββββββββββββ
Apakah kertas pertama berubah?
Tidak.
Jadi:
flight β BNB 289
flightNum β BNB 9999
Inilah yang disebut pass by value dalam terminology lecture.
6. Sekarang bagian person
Kita punya:
let person = {
name: "John",
passport: 123456
};
person adalah object.
Object adalah reference type.
Secara sederhana:
person ββββββ Object A
{
name: "John",
passport: 123456
}
Kemudian:
checkIn(flight, person);
Parameter:
passenger
mendapatkan reference yang sama.
Jadi:
person βββββββ
β
Object A
{
name: "John",
passport: 123456
}
β
passenger ββββ
Ini bagian yang sangat penting.
person dan passenger menunjuk object yang sama.
7. Lalu function mengubah passenger.name
Di dalam function:
passenger.name = "Mr " + passenger.name;
Awalnya:
passenger.name
β
"John"
Kemudian:
"Mr " + "John"
menghasilkan:
"Mr John"
Lalu:
passenger.name = "Mr John";
mengubah object.
Object sekarang:
Object A
{
name: "Mr John",
passport: 123456
}
Tapi ingat:
person βββββββ
β
Object A
{
name: "Mr John"
...
}
β
passenger ββββ
Karena person dan passenger menunjuk object yang sama, person juga melihat perubahan tersebut.
8. Inilah perbedaan utama kedua kasus
Primitive
let flight = "BNB 289";
checkIn(flight);
Kemudian:
flightNum = "BNB 9999";
Hanya mengubah parameter.
flight β "BNB 289"
flightNum β "BNB 9999"
Object
let person = {
name: "John"
};
checkIn(person);
Kemudian:
passenger.name = "Mr John";
Mengubah object yang sama.
person βββββββ
β
Object
name: Mr John
β
passenger ββββ
9. Visual paling penting dari lecture
Coba hafalkan diagram ini.
Primitive
Sebelum function:
flight
β
"BNB 289"
Saat function dipanggil:
flight
β
"BNB 289"
flightNum
β
"BNB 289"
Kemudian:
flightNum = "BNB 9999";
menjadi:
flight
β
"BNB 289"
flightNum
β
"BNB 9999"
Terpisah.
Object
Sebelum function:
person ββββββ Object A
name: John
Saat function dipanggil:
person βββββββ
β
Object A
name: John
β
passenger ββββ
Kemudian:
passenger.name = "Mr John";
menjadi:
person βββββββ
β
Object A
name: Mr John
β
passenger ββββ
Object yang sama berubah.
10. Analogi yang paling mudah: fotokopi vs alamat rumah
Ini sangat cocok untuk mengingat lecture sebelumnya dan lecture sekarang.
Primitive = fotokopi
flight
β
"BNB 289"
β copy value
flightNum
β
"BNB 289"
Seperti:
Saya punya dokumen. Saya fotokopi dokumen itu untuk kamu.
Kalau kamu mencoret fotokopimu:
flightNum β "BNB 9999"
dokumen asli:
flight β "BNB 289"
tetap aman.
Object = alamat rumah
person
β
alamat rumah
β
π Object
Ketika diberikan ke function:
person βββββββ
β
π
β
passenger ββββ
passenger mendapatkan alamat rumah yang sama.
Kalau passenger mengganti sofa di rumah:
passenger.name = "Mr John";
orang yang memiliki alamat yang sama (person) juga melihat rumah yang sudah berubah.
11. Perhatikan: parameter function adalah variable juga
Ini juga penting.
Ketika kamu menulis:
function checkIn(flightNum, passenger) {
}
flightNum dan passenger adalah parameter.
Ketika function dipanggil:
checkIn(flight, person);
argument:
flight
person
digunakan untuk menginisialisasi parameter:
flight β flightNum
person β passenger
Secara konsep:
argument parameter
flight ββββββββ flightNum
"BNB 289" "BNB 289"
person ββββββββ passenger
reference reference
β β
βββββββββββββ¬ββββββββββββββ
β
Object A
12. Hubungannya dengan scope
Ini juga sebenarnya menyambung ke lecture scope.
Ketika function dipanggil:
checkIn(flight, person);
function memiliki environment/ruang lokalnya sendiri.
Di dalam function terdapat:
checkIn()
βββ flightNum
βββ passenger
Sedangkan di luar ada:
Global
βββ flight
βββ person
Jadi:
GLOBAL
flight ββββββ "BNB 289"
person ββββββ Object A
β
β
FUNCTION
β
flightNum ββββ "BNB 289"
passenger ββββ Object A
Ini juga menjelaskan kenapa:
flightNum = "BNB 9999";
tidak mengubah variable flight.
flightNum adalah parameter/local variable yang berbeda.
13. Jangan salah: passenger bukan object baru
Ketika:
checkIn(flight, person);
dan:
function checkIn(flightNum, passenger)
passenger bukan object baru.
Ini bukan:
person β Object A
passenger β Object B
melainkan:
person βββββββ
β
Object A
β
passenger ββββ
Ini yang membuat mutation terlihat dari luar function.
14. Contoh sederhana tanpa flight
Supaya lebih mudah, kita sederhanakan.
function changeName(user) {
user.name = "Budi";
}
let person = {
name: "John"
};
changeName(person);
console.log(person.name);
Hasil:
Budi
Kenapa?
Awalnya:
person βββ { name: "John" }
Masuk function:
person ββββββ
β
{ name: "John" }
β
user ββββββββ
Kemudian:
user.name = "Budi";
Object menjadi:
person ββββββ
β
{ name: "Budi" }
β
user ββββββββ
Jadi person.name berubah.
15. Tapi bagaimana kalau kita melakukan reassignment?
Ini bagian yang sangat penting.
Perhatikan:
function changeUser(user) {
user = {
name: "Budi"
};
}
let person = {
name: "John"
};
changeUser(person);
console.log(person.name);
Hasil:
John
Kenapa?
Karena kita tidak mengubah object lama.
Kita melakukan:
user = {
name: "Budi"
};
Artinya parameter user sekarang diarahkan ke object baru.
Sebelum:
person βββββββ
β
Object A
{ name: "John" }
β
user βββββββββ
Setelah:
person ββββββ Object A
{ name: "John" }
user ββββββββ Object B
{ name: "Budi" }
person tetap menunjuk Object A.
Jadi:
person.name
tetap:
John
16. Ini adalah pasangan konsep yang wajib kamu kuasai
MUTATION
contohnya:
user.name = "Budi";
β mengubah object yang sama.
Sedangkan:
REASSIGNMENT
contohnya:
user = {
name: "Budi"
};
β parameter user diarahkan ke object baru.
Perhatikan perbedaannya:
user.name = ...
β
property
object lama berubah
vs:
user = ...
β
variable/reference diganti
17. Ini akan sangat sering muncul di coding nyata
Misalnya kamu punya:
let cart = {
items: []
};
Kemudian function:
function addItem(cart) {
cart.items.push("Laptop");
}
Lalu:
addItem(cart);
cart.items berubah karena function mengakses object yang sama.
Tetapi kalau:
function replaceCart(cart) {
cart = {
items: ["Laptop"]
};
}
itu tidak mengganti variable cart di luar function.
Ini perbedaan yang sangat penting dalam JavaScript.
18. Bagaimana dengan array?
Array juga reference type.
Misalnya:
function addNumber(numbers) {
numbers.push(40);
}
let arr = [10, 20, 30];
addNumber(arr);
console.log(arr);
Hasil:
[10, 20, 30, 40]
Karena:
arr βββββββββ
β
[10,20,30]
β
numbers βββββ
Kemudian:
numbers.push(40);
mengubah array yang sama.
19. Tetapi kalau array-nya di-reassign
function replaceArray(numbers) {
numbers = [100, 200];
}
let arr = [10, 20, 30];
replaceArray(arr);
console.log(arr);
Hasil:
[10, 20, 30]
Karena:
arr ββββββ Array A
[10,20,30]
numbers ββ Array B
[100,200]
Parameter numbers berubah arah, tetapi arr di luar function tetap menunjuk Array A.
20. Sekarang kita luruskan istilah “pass by reference”
Lecture mengatakan:
Primitive β pass by value
Object β pass by reference
Ini adalah cara mengajar yang sangat umum dan berguna untuk memahami behavior.
Tetapi secara teknis, JavaScript sebenarnya lebih tepat disebut:
JavaScript selalu pass-by-value.
Lalu bagaimana object bisa berubah?
Karena value yang disalin ketika object dikirim adalah reference menuju object tersebut.
Ini memang terdengar agak rumit, jadi lihat diagram berikut.
21. Versi teknis yang lebih akurat
Misalnya:
let person = {
name: "John"
};
function change(user) {
user.name = "Budi";
}
change(person);
Saat person dikirim:
person
β
reference ββββββ Object A
Reference tersebut disalin ke parameter user:
person βββββββ
β
Object A
β
user βββββββββ
Jadi yang sebenarnya terjadi:
value dari person
β
reference
β
disalin ke user
Karena kedua reference menunjuk Object A yang sama, mutation terlihat dari luar.
Jadi bukan:
“Function mendapatkan variable person secara langsung.”
Melainkan:
“Function mendapatkan salinan value yang kebetulan merupakan reference ke object yang sama.”
22. Buktinya: reassignment tidak memengaruhi luar
Ini membuktikan bahwa JavaScript tidak benar-benar memberikan akses langsung ke variable luar.
function test(obj) {
obj = {
name: "Budi"
};
}
let person = {
name: "John"
};
test(person);
console.log(person);
Hasil:
{
name: "John"
}
Kenapa?
Karena reference-nya disalin:
person ββββββ Object A
obj βββββββββ Object A
Kemudian:
obj = Object B;
menjadi:
person ββββββ Object A
obj βββββββββ Object B
person tidak ikut pindah.
Ini adalah bukti bahwa parameter obj adalah variable/binding tersendiri.
23. Jadi kalimat paling akurat
Daripada:
“Object selalu pass by reference.”
lebih akurat mengatakan:
Object reference-nya disalin ketika dikirim ke function. Karena reference tersebut menunjuk object yang sama, mutation terhadap object dapat terlihat dari luar function.
Untuk pemula, kamu boleh menggunakan mental model:
Primitive β copy value
Object β copy reference
Itu sudah sangat membantu.
Nanti ketika sudah lebih advanced, ingat:
JavaScript β pass-by-value
Object value β reference
24. Hubungan dengan ===
Konsep ini juga nyambung langsung dengan lecture sebelumnya.
Misalnya:
let person = {
name: "John"
};
function check(user) {
console.log(user === person);
}
check(person);
Hasil:
true
Karena user dan person memiliki reference menuju object yang sama.
Secara mental:
person βββββ
β
Object A
β
user βββββββ
25. Contoh yang sering menjebak
let person1 = {
name: "John"
};
let person2 = {
name: "John"
};
Kemudian:
function check(user) {
console.log(user === person1);
}
check(person2);
Hasil:
false
Karena:
person1 βββ Object A
person2 βββ Object B
Walaupun:
Object A = { name: "John" }
Object B = { name: "John" }
Object-nya berbeda.
26. Sekarang hubungkan semua lecture
Kita sudah belajar beberapa konsep yang sebenarnya saling terhubung:
Primitive / Object
β
Value / Reference
β
Assignment
β
Function arguments
β
Pass by value / reference
β
Mutation / Reassignment
Dan semuanya saling berkaitan.
27. Flow lengkap dari contoh lecture
Mari kita ikuti dari awal sampai akhir.
Step 1 β Buat flight
let flight = "BNB 289";
flight β "BNB 289"
Primitive.
Step 2 β Buat person
let person = {
name: "John",
passport: 123456
};
person βββ Object A
Reference type.
Step 3 β Panggil function
checkIn(flight, person);
Secara mental:
flight
β copy value
flightNum
person
β copy reference
passenger
Step 4 β Ubah flight number
flightNum = "BNB 9999";
Hanya:
flightNum β "BNB 9999"
flight tetap:
flight β "BNB 289"
Step 5 β Ubah nama passenger
passenger.name = "Mr John";
Karena:
passenger βββ
β
Object A
β
person ββββββ
Object A berubah.
Maka:
person.name
β
"Mr John"
28. Cheat sheet
| Situasi | Apa yang disalin? | Efek |
|---|---|---|
let b = a, a primitive | Value | Independent |
let b = a, a object | Reference | Bisa menunjuk object sama |
| Function menerima Number/String | Value | Reassignment parameter tidak memengaruhi luar |
| Function menerima Object/Array | Reference value | Mutation object bisa terlihat dari luar |
obj.x = ... | Mutation | Object bersama berubah |
obj = {...} | Reassignment | Hanya variable tersebut yang pindah |
29. Pola yang harus kamu hafalkan
Pola 1 β Primitive
let a = 10;
function change(x) {
x = 20;
}
change(a);
console.log(a);
Hasil:
10
Karena:
a β 10
x β 10
kemudian:
x β 20
a tetap 10.
Pola 2 β Object mutation
let a = {
value: 10
};
function change(x) {
x.value = 20;
}
change(a);
console.log(a.value);
Hasil:
20
Karena:
a βββββ
β
Object A
β
x βββββ
Object yang sama dimutasi.
Pola 3 β Object reassignment
let a = {
value: 10
};
function change(x) {
x = {
value: 20
};
}
change(a);
console.log(a.value);
Hasil:
10
Karena:
a β Object A { value: 10 }
x β Object B { value: 20 }
30. Satu diagram super penting
Kalau kamu hanya mau mengingat satu diagram dari lecture ini, ingat ini:
PRIMITIVE
ββββββββββββββββββββββββ
outside function
a β 10
copy value
β
x β 10
x = 20
a β 10
x β 20
Sedangkan:
OBJECT
ββββββββββββββββββββββββ
outside function
a βββββββββββ
β
Object A
β
x βββββββββββ
x.value = 20
a βββββββββββ
β
Object A
value: 20
β
x βββββββββββ
31. Inti lecture dalam bahasa paling sederhana
Kalau dibuat sesederhana mungkin:
Kalau function menerima primitive, function mendapatkan salinan nilainya. Mengubah parameter tidak mengubah variable asli.
Contoh:
let age = 20;
function change(x) {
x = 30;
}
change(age);
// age tetap 20
Sedangkan:
Kalau function menerima object/array, parameter mendapatkan salinan reference menuju object yang sama. Jadi kalau object tersebut dimutasi, perubahan bisa terlihat dari variable asli.
Contoh:
let user = {
name: "John"
};
function change(x) {
x.name = "Budi";
}
change(user);
// user.name β "Budi"
Tetapi:
function change(x) {
x = {
name: "Budi"
};
}
tidak mengganti object di luar.
π§ Mindset untuk menghadapi soal berikutnya
Setiap kali melihat function menerima argument, jangan langsung melihat hasilnya. Tanya 3 hal:
1. Apa tipe data yang dikirim?
β
primitive atau object?
2. Apa yang dilakukan di dalam function?
β
mutation atau reassignment?
3. Apakah saya sedang mengubah
object-nya atau reference/parameter-nya?
Lalu kamu bisa memprediksi hasilnya.
Rumus mentalnya:
PRIMITIVE
β copy value
β ubah parameter
β variable luar tidak berubah
OBJECT / ARRAY
β copy reference
β mutation
β variable luar bisa ikut melihat perubahan
OBJECT / ARRAY
β reassignment parameter
β variable luar tidak berubah
Dan ini adalah fondasi yang sangat penting sebelum masuk ke bagian berikutnya tentang bagaimana JavaScript benar-benar bekerja di dalam browser. Di bagian itu kamu akan mulai melihat konsep seperti execution context, call stack, memory, creation phase, execution phase, dan bagaimana function dipanggilβyang sebenarnya akan membuat diagram-diagram value/reference tadi jauh lebih masuk akal.