Tipe-tipe primitif (angka, string, dll.) Dilewatkan oleh nilai, tetapi objek tidak diketahui, karena keduanya dapat lewat-oleh-nilai (dalam kasus kami menganggap bahwa variabel yang memegang objek sebenarnya adalah referensi ke objek ) dan lulus-oleh-referensi (ketika kita menganggap bahwa variabel ke objek memegang objek itu sendiri).
Meskipun pada akhirnya tidak terlalu penting, saya ingin tahu apa cara yang benar untuk menyajikan argumen yang lolos dari konvensi. Apakah ada kutipan dari spesifikasi JavaScript, yang mendefinisikan apa yang seharusnya menjadi semantik mengenai ini?
javascript
pass-by-reference
pass-by-value
Danail Nachev
sumber
sumber
var x=3, y=x; f(x); alert(y === x);
fungsif()
dapat membuat laporan peringatanfalse
dan tidaktrue
. Dalam JavaScript, itu tidak mungkin, jadi itu bukan pass-by-reference. Adalah baik bahwa mungkin untuk meneruskan referensi ke objek yang dapat dimodifikasi, tetapi bukan itu yang dimaksud dengan "lulus dengan referensi". Seperti yang saya katakan, sangat disayangkan bahwa terminologinya sangat membingungkan.Jawaban:
Sangat menarik dalam JavaScript. Pertimbangkan contoh ini:
Ini menghasilkan output:
obj1
bukan referensi sama sekali, maka perubahan tidakobj1.item
akan berpengaruh pada bagianobj1
luar fungsi.num
akan100
, danobj2.item
akan membaca"changed"
.Alih-alih, situasinya adalah bahwa item yang diteruskan dilewatkan dengan nilai. Tetapi item yang dilewatkan oleh nilai itu sendiri adalah referensi. Secara teknis, ini disebut call-by-sharing .
Dalam istilah praktis, ini berarti bahwa jika Anda mengubah parameter itu sendiri (seperti dengan
num
danobj2
), itu tidak akan memengaruhi item yang dimasukkan ke dalam parameter. Tetapi jika Anda mengubah INTERNAL parameter, itu akan menyebar kembali (seperti halnyaobj1
).sumber
item
properti objek yang dirujuk oleh obj1, Anda mengubah nilai properti item yang awalnya disetel ke "tidak berubah". Ketika Anda memberikan obj2 nilai {item: "berubah"} Anda mengubah referensi ke objek baru (yang segera keluar dari ruang lingkup ketika fungsi keluar). Menjadi lebih jelas apa yang terjadi jika Anda menamai fungsi params hal-hal seperti numf, obj1f, dan obj2f. Kemudian Anda melihat bahwa params menyembunyikan nama var eksternal.ref
kata kunci.) Biasanya Anda hanya akan memiliki fungsi mengembalikan objek baru, dan melakukan tugas pada titik di mana Anda memanggil fungsi. Misalnya,foo = GetNewFoo();
alih-alihGetNewFoo(foo);
var obj1 = { item: 'unchanged' }; var obj2 = obj1; obj2.item = 'changed';
dan akan mengamati efek yang sama seperti pada contoh Anda. Karena itu saya pribadi merujuk jawaban Tim GoodmanItu selalu melewati nilai, tetapi untuk objek nilai variabel adalah referensi. Karena itu, ketika Anda melewati objek dan mengubah anggotanya , perubahan itu tetap ada di luar fungsi. Ini membuatnya terlihat seperti referensi lewat. Tetapi jika Anda benar-benar mengubah nilai variabel objek Anda akan melihat bahwa perubahan itu tidak bertahan, membuktikan itu benar-benar melewati nilai.
Contoh:
Keluaran:
sumber
changeObject
, saya telah berubahx
untuk berisi referensi ke objek baru.x = {member:"bar"};
setara denganx = new Object(); x.member = "bar";
Apa yang saya katakan juga berlaku untuk C #, omong-omong.ref
kata kunci, Anda dapat melewati referensi dengan referensi (alih-alih default melewati referensi dengan nilai), dan kemudian perubahan ke menunjuk kenew Object()
akan tetap ada .Variabel tidak "menahan" objek; itu memegang referensi. Anda dapat menetapkan referensi itu ke variabel lain, dan sekarang keduanya merujuk objek yang sama. Itu selalu melewati nilai (bahkan ketika nilai itu adalah referensi ...).
Tidak ada cara untuk mengubah nilai yang dimiliki oleh variabel yang diteruskan sebagai parameter, yang akan mungkin jika JavaScript didukung lewat referensi.
sumber
Dua sen saya ... Ini adalah cara saya memahaminya. (Jangan ragu untuk mengoreksi saya jika saya salah)
Saatnya membuang semua yang Anda ketahui tentang nilai / referensi.
Karena dalam JavaScript, tidak masalah apakah itu diteruskan oleh nilai atau referensi atau apa pun. Yang penting adalah mutasi vs penugasan parameter dilewatkan ke fungsi.
OK, biarkan saya melakukan yang terbaik untuk menjelaskan apa yang saya maksud. Katakanlah Anda memiliki beberapa objek.
Apa yang telah kami lakukan adalah "tugas" ... Kami telah menetapkan 2 objek kosong terpisah ke variabel "object1" dan "object2".
Sekarang, katakanlah kita menyukai objek1 lebih baik ... Jadi, kita "menetapkan" variabel baru.
Selanjutnya, untuk alasan apa pun, kami memutuskan bahwa kami lebih suka objek 2. Jadi, kami hanya melakukan sedikit penugasan ulang.
Tidak ada yang terjadi pada object1 atau object2. Kami belum mengubah data apa pun. Yang kami lakukan hanyalah menetapkan ulang apa objek favorit kami. Penting untuk mengetahui bahwa object2 dan favoriteObject keduanya ditugaskan untuk objek yang sama. Kita dapat mengubah objek itu melalui salah satu variabel tersebut.
OK, sekarang mari kita lihat primitif seperti string misalnya
Sekali lagi, kami memilih favorit.
Variabel favoriteString dan string1 kami ditugaskan ke 'Hello world'. Sekarang, bagaimana jika kita ingin mengubah Stringsing favorit kita ??? Apa yang akan terjadi???
Uh oh .... Apa yang terjadi. Kami tidak dapat mengubah string1 dengan mengubahString favorit ... Mengapa ?? Karena kami tidak mengubah objek string kami . Yang kami lakukan adalah "RE ASSIGN" variabel favoriteString ke string baru. Ini pada dasarnya memutusnya dari string1. Pada contoh sebelumnya, ketika kami mengganti nama objek kami, kami tidak menetapkan apa pun. (Yah, bukan ke variabel itu sendiri , ... kami, bagaimanapun, menetapkan properti nama ke string baru.) Sebaliknya, kami hanya bermutasi objek yang menjaga koneksi antara 2 variabel dan objek yang mendasarinya. (Bahkan jika kita ingin memodifikasi atau mengubah objek string itu sendiri, kami tidak dapat melakukannya, karena string sebenarnya tidak dapat diubah dalam JavaScript.)
Sekarang, ke fungsi dan melewati parameter .... Ketika Anda memanggil fungsi, dan melewatkan parameter, apa yang Anda lakukan pada dasarnya adalah "tugas" ke variabel baru, dan berfungsi persis sama seperti jika Anda hanya ditugaskan menggunakan tanda sama dengan (=).
Ambil contoh ini.
Sekarang, hal yang sama, tetapi dengan suatu fungsi
OK, sekarang mari kita berikan beberapa contoh menggunakan objek saja ... pertama, tanpa fungsi.
Sekarang, hal yang sama, tetapi dengan pemanggilan fungsi
OK, jika Anda membaca seluruh posting ini, mungkin Anda sekarang memiliki pemahaman yang lebih baik tentang cara kerja pemanggilan fungsi dalam JavaScript. Tidak masalah apakah sesuatu dilewatkan dengan referensi atau berdasarkan nilai ... Yang penting adalah penugasan vs mutasi.
Setiap kali Anda melewatkan variabel ke suatu fungsi, Anda "Menugaskan" ke apa pun nama variabel parameternya, sama seperti jika Anda menggunakan tanda sama dengan (=).
Selalu ingat bahwa tanda sama dengan (=) berarti tugas. Selalu ingat bahwa meneruskan parameter ke fungsi dalam JavaScript juga berarti tugas. Mereka sama dan 2 variabel terhubung dengan cara yang persis sama (artinya tidak, kecuali Anda menghitung bahwa mereka ditugaskan ke objek yang sama).
Satu-satunya waktu "memodifikasi variabel" mempengaruhi variabel yang berbeda adalah ketika objek yang mendasarinya dimutasi (dalam hal ini Anda belum mengubah variabel, tetapi objek itu sendiri.
Tidak ada gunanya membuat perbedaan antara objek dan primitif, karena ia bekerja dengan cara yang persis sama seolah-olah Anda tidak memiliki fungsi dan hanya menggunakan tanda sama dengan untuk menetapkan ke variabel baru.
Satu-satunya gotcha adalah ketika nama variabel yang Anda masukkan ke dalam fungsi sama dengan nama parameter fungsi. Ketika ini terjadi, Anda harus memperlakukan parameter di dalam fungsi seolah-olah itu adalah variabel baru pribadi untuk fungsi (karena itu)
sumber
foo(char *a){a="hello";}
tidak melakukan apa-apa, tetapi jika Anda melakukannyafoo(char *a){a[0]='h';a[1]='i';a[2]=0;}
diubah di luar karenaa
lokasi memori dilewatkan oleh nilai yang mereferensikan string (char array). Melewati struct (mirip dengan objek js) dengan nilai dalam C diizinkan, tetapi tidak disarankan. JavaScript hanya menerapkan praktik terbaik ini dan menyembunyikan cruft yang tidak perlu dan biasanya tidak diinginkan ... dan tentu saja membuatnya lebih mudah dibaca.source = { "id":"1"}; copy = source /*this is wrong*/; copy.id="2"
itu sumber masih {"id": "1"}?Pertimbangkan yang berikut ini:
Jadi,
lupakan "pass by reference / value"jangan terpaku pada "pass by reference / value" karena:Untuk menjawab pertanyaan Anda: petunjuk diberikan.
Beberapa komentar terakhir:
sumber
{'George', 1}
nilai, tetapi hanya menggunakan salah satunya saja, lalu bagaimana yang lain dikelola? Dan apa yang terjadi ketika saya menetapkan variabel ke nilai variabel lain? Apakah saya kemudian menunjuk ke sebuah pointer, atau menunjuk ke pointee dari operan yang tepat? Apakahvar myExistingVar = {"blah", 42}; var obj = myExistingVar;
menghasilkanobj
menunjuk ke{"blah", 42}
, atau kemyExistingVar
?1)
saya menjalankan profil memori di alat dev browser untuk fungsi loop seperti yang Anda jelaskan dan melihat lonjakan dalam penggunaan memori selama proses looping. Ini tampaknya menunjukkan bahwa objek identik baru memang sedang dibuat di setiap iterasi dari loop. Ketika paku tiba-tiba jatuh, pengumpul sampah baru saja membersihkan sekelompok benda yang tidak digunakan ini.2)
Mengenai sesuatu sepertivar a = b
, javascript tidak menyediakan mekanisme untuk menggunakan pointer dan variabel tidak pernah dapat menunjuk ke pointer (seperti yang Anda dapat dalam C), meskipun mesin javascript yang mendasarinya pasti menggunakannya. Jadi ...var a = b
akan mengarahkana
"ke titik operasi operan yang tepat"Objek di luar fungsi dilewatkan ke fungsi dengan memberikan referensi ke objek luar.
Saat Anda menggunakan referensi itu untuk memanipulasi objeknya, objek di luar akan terpengaruh. Namun, jika di dalam fungsi Anda memutuskan untuk mengarahkan referensi ke sesuatu yang lain, Anda tidak mempengaruhi objek di luar sama sekali, karena semua yang Anda lakukan adalah mengarahkan kembali referensi ke sesuatu yang lain.
sumber
Pikirkan seperti ini: Itu selalu melewati nilai. Namun, nilai suatu objek bukanlah objek itu sendiri, tetapi referensi ke objek itu.
Berikut ini sebuah contoh, melewati angka (tipe primitif)
Mengulanginya dengan objek menghasilkan hasil yang berbeda:
Satu lagi contoh:
sumber
Sebuah penjelasan yang sangat rinci tentang menyalin, melewati dan membandingkan dengan nilai dan dengan referensi dalam bab ini dari "JavaScript: Panduan pasti" buku.
sumber
JavaScript selalu dinilai berdasarkan nilai ; semuanya bertipe nilai.
Objek adalah nilai, dan fungsi anggota dari objek adalah nilai itu sendiri (ingat bahwa fungsi adalah objek kelas satu dalam JavaScript). Juga, berkenaan dengan konsep bahwa segala sesuatu dalam JavaScript adalah objek ; ini salah. String, simbol, angka, boolean, null, dan undefined adalah primitif .
Kadang-kadang mereka dapat memanfaatkan beberapa fungsi dan properti anggota yang diwarisi dari prototipe dasar mereka, tetapi ini hanya untuk kenyamanan. Itu tidak berarti bahwa mereka adalah objek itu sendiri. Coba yang berikut ini untuk referensi:
Di kedua lansiran Anda akan menemukan nilai yang tidak terdefinisi.
sumber
x = "teste"; x.foo = 12;
dll. Hanya karena properti tidak persisten, itu tidak berarti itu bukan objek. Seperti yang dikatakan MDN: Dalam JavaScript, hampir semuanya adalah objek. Semua tipe primitif kecuali null dan undefined diperlakukan sebagai objek. Mereka dapat diberi properti (properti yang ditugaskan dari beberapa jenis tidak persisten), dan mereka memiliki semua karakteristik objek. linkDalam JavaScript, jenis nilai semata-mata mengontrol apakah nilai itu akan ditetapkan oleh copy-nilai atau oleh copy-referensi .
Nilai-nilai primitif selalu ditetapkan / diteruskan oleh copy-nilai :
null
undefined
ES6
Nilai gabungan selalu ditetapkan / diteruskan dengan salinan-rujukan
Sebagai contoh
Dalam cuplikan di atas, karena
2
merupakan skalar primitif,a
memegang satu salinan awal dari nilai itu, danb
diberikan salinan lain dari nilai tersebut. Saat berubahb
, Anda sama sekali tidak mengubah nilainyaa
.Tetapi keduanya
c
dand
merupakan referensi terpisah untuk nilai bersama yang sama[1,2,3]
, yang merupakan nilai majemuk. Penting untuk dicatat bahwa tidak adac
ataud
lebih "memiliki"[1,2,3]
nilai - keduanya hanya referensi rekan yang setara dengan nilai. Jadi, ketika menggunakan salah satu referensi untuk memodifikasi (.push(4)
) nilai bersama aktualarray
itu sendiri, itu hanya mempengaruhi satu nilai yang dibagikan, dan kedua referensi akan referensi nilai yang baru dimodifikasi[1,2,3,4]
.Ketika kami membuat tugas
b = [4,5,6]
, kami sama sekali tidak melakukan apa pun untuk memengaruhi di manaa
masih merujuk ([1,2,3]
). Untuk melakukan itu,b
harus menjadi pointera
daripada referensi kearray
- tetapi tidak ada kemampuan seperti itu ada di JS!Ketika kami melewati argumen
a
, itu memberikan salinana
referensi kex
.x
dana
referensi terpisah menunjuk pada nilai yang sama[1,2,3]
. Sekarang, di dalam fungsi, kita bisa menggunakan referensi itu untuk mengubah nilai itu sendiri (push(4)
). Tetapi ketika kita membuat tugasx = [4,5,6]
, ini sama sekali tidak mempengaruhi di mana referensi awala
menunjuk - masih menunjuk pada nilai (sekarang dimodifikasi)[1,2,3,4]
.Untuk secara efektif meneruskan nilai gabungan (seperti a
array
) dengan nilai-salinan, Anda perlu secara manual membuat salinannya, sehingga referensi yang diteruskan masih tidak menunjuk ke aslinya. Sebagai contoh:Nilai majemuk (objek, array, dll) yang dapat dilewati oleh referensi-salinan
Di sini,
obj
bertindak sebagai pembungkus untuk properti primitif skalara
. Ketika diteruskan kefoo(..)
, salinanobj
referensi dilewatkan dan diatur kewrapper
parameter. Kita sekarang dapat menggunakanwrapper
referensi untuk mengakses objek bersama, dan memperbarui propertinya. Setelah fungsi selesai,obj.a
akan melihat nilai yang diperbarui42
.Sumber
sumber
baik, ini tentang 'kinerja' dan 'kecepatan' dan dalam kata sederhana 'manajemen memori' dalam bahasa pemrograman.
dalam javascript kita dapat meletakkan nilai dalam dua lapisan: type1 -
objects
dan type2 -semua jenis nilai lainnya sepertistring
&boolean
& dlljika Anda membayangkan memori seperti kotak di bawah ini yang di masing-masingnya hanya satu nilai type2 yang dapat disimpan:
setiap type2-value (hijau) adalah kotak tunggal sementara nilai type1 (biru) adalah grup dari mereka :
intinya adalah bahwa jika Anda ingin menunjukkan nilai type2, alamatnya sederhana tetapi jika Anda ingin melakukan hal yang sama untuk nilai type1 itu tidak mudah sama sekali! :
dan dalam cerita yang lebih rumit:
jadi di sini referensi dapat menyelamatkan kita:
sedangkan panah hijau di sini adalah variabel tipikal, yang ungu adalah variabel objek, jadi karena panah hijau (variabel tipikal) hanya memiliki satu tugas (dan itu menunjukkan nilai tipikal) kita tidak perlu memisahkan nilainya dari jadi kami memindahkan panah hijau dengan nilai ke mana pun ia pergi dan dalam semua tugas, fungsi dan seterusnya ...
tetapi kita tidak dapat melakukan hal yang sama dengan panah ungu, kita mungkin ingin memindahkan sel 'john' di sini atau banyak hal lainnya ..., sehingga panah ungu akan menempel pada tempatnya dan hanya panah khas yang ditugaskan untuk itu akan bergerak ...
situasi yang sangat membingungkan adalah ketika Anda tidak dapat menyadari bagaimana perubahan variabel referensi Anda, mari kita lihat contoh yang sangat bagus:
sumber
Ini sedikit penjelasan untuk pass by value dan pass by reference (JavaScript). Dalam konsep ini, mereka berbicara tentang melewati variabel dengan referensi dan melewati variabel dengan referensi.
Lewati nilai (tipe primitif)
Lewati dengan referensi (objek)
c
, dan menunjuk ke beberapa memori, misalnya (0x012).d
menunjuk ke lokasi yang sama (0x012).Kasus khusus, lulus dengan referensi (objek)
sumber
c
diatur ke salinan referensi objek baru.Dalam JavaScript, saat menetapkan objek ke variabel, nilai yang ditetapkan ke variabel adalah referensi ke objek:
sumber
Semantik!! Menetapkan definisi konkret akan membuat beberapa jawaban dan komentar tidak cocok karena mereka tidak menggambarkan hal yang sama bahkan ketika menggunakan kata dan frasa yang sama, tetapi sangat penting untuk melewati kebingungan (terutama untuk programmer baru).
Pertama-tama, ada beberapa tingkatan abstraksi yang tampaknya tidak semua orang pahami. Programer yang lebih baru yang telah belajar bahasa generasi ke-4 atau ke-5 mungkin mengalami kesulitan membungkus pikiran mereka di sekitar konsep yang akrab dengan perakitan atau programmer C tidak bertahap oleh pointer ke pointer ke pointer. Pass-by-reference tidak hanya berarti kemampuan untuk mengubah objek yang direferensikan menggunakan variabel parameter fungsi.
Variabel : Konsep gabungan simbol yang mereferensikan nilai pada lokasi tertentu dalam memori. Istilah ini biasanya terlalu dimuat untuk digunakan sendiri dalam membahas detail.
Simbol : String teks yang digunakan untuk merujuk ke variabel (yaitu nama variabel).
Nilai : Bit tertentu disimpan dalam memori dan direferensikan menggunakan simbol variabel.
Lokasi memori : Di mana nilai variabel disimpan. (Lokasi itu sendiri diwakili oleh angka yang terpisah dari nilai yang disimpan di lokasi.)
Parameter fungsi : Variabel dideklarasikan dalam definisi fungsi, digunakan untuk referensi variabel yang diteruskan ke fungsi.
Argumen fungsi : Variabel di luar fungsi yang diteruskan ke fungsi oleh pemanggil.
Variabel objek : Variabel yang nilai dasarnya yang mendasarinya bukan "objek" itu sendiri, melainkan nilainya adalah pointer (nilai lokasi memori) ke lokasi lain di memori tempat data aktual objek disimpan. Dalam sebagian besar bahasa generasi yang lebih tinggi, aspek "penunjuk" secara efektif disembunyikan oleh rujukan otomatis dalam berbagai konteks.
Variabel primitif : Variabel yang nilainya IS nilai sebenarnya. Bahkan konsep ini dapat menjadi rumit dengan konteks auto-boxing dan objek-seperti dari berbagai bahasa, tetapi ide-ide umum adalah bahwa nilai variabel adalah nilai aktual yang diwakili oleh simbol variabel daripada penunjuk ke lokasi memori lain.
Argumen fungsi dan parameter bukan hal yang sama. Juga, nilai variabel bukanlah objek variabel (seperti yang telah ditunjukkan oleh berbagai orang, tetapi tampaknya diabaikan). Perbedaan-perbedaan ini sangat penting untuk pemahaman yang tepat.
Pass-by-value atau Call-by-sharing (untuk objek): Nilai argumen fungsi COPIED ke lokasi memori lain yang direferensikan oleh simbol parameter fungsi (terlepas dari apakah itu di stack atau heap). Dengan kata lain, parameter fungsi menerima salinan dari nilai argumen yang diteruskan ... DAN (kritis) nilai argumen TIDAK PERNAH DIPERBARUI / DIUBAH / DIUBAH oleh fungsi pemanggilan. Ingat, nilai variabel objek BUKAN objek itu sendiri, melainkan itu adalah pointer ke objek, jadi meneruskan variabel objek dengan nilai menyalin pointer ke variabel parameter fungsi. Nilai parameter fungsi menunjuk ke objek yang sama persis di memori. Objek data itu sendiri dapat diubah secara langsung melalui parameter fungsi, TETAPI nilai argumen fungsi TIDAK PERNAH DIPERBARUI, sehingga akan terus menunjuk ke yang samaobjek di seluruh dan bahkan setelah pemanggilan fungsi (bahkan jika data objeknya diubah atau jika parameter fungsi diberikan objek yang berbeda sama sekali). Tidaklah tepat untuk menyimpulkan bahwa argumen fungsi disahkan oleh referensi hanya karena objek yang direferensikan dapat diperbarui melalui variabel parameter fungsi.
Referensi Panggilan / Lulus : Nilai argumen fungsi dapat / akan diperbarui secara langsung oleh parameter fungsi terkait. Jika itu membantu, parameter fungsi menjadi "alias" yang efektif untuk argumen - mereka secara efektif merujuk pada nilai yang sama di lokasi memori yang sama. Jika argumen fungsi adalah variabel objek, kemampuan untuk mengubah data objek tidak berbeda dari kasus pass-by-value karena parameter fungsi masih akan menunjuk ke objek yang sama dengan argumen. Tetapi dalam kasus variabel objek, jika parameter fungsi diatur ke objek yang sama sekali berbeda, maka argumen juga akan menunjuk ke objek yang berbeda - ini tidak terjadi dalam kasus pass-by-value.
JavaScript tidak lulus dengan referensi. Jika Anda membaca dengan seksama, Anda akan menyadari bahwa semua pendapat yang bertentangan salah mengerti apa yang dimaksud dengan nilai demi nilai dan mereka secara keliru menyimpulkan bahwa kemampuan untuk memperbarui data objek melalui parameter fungsi identik dengan "nilai demi nilai".
Objek klon / salin : Objek baru dibuat dan data objek asli disalin. Ini bisa berupa salinan dalam atau salinan dangkal, tetapi intinya adalah bahwa objek baru dibuat. Membuat salinan objek adalah konsep terpisah dari nilai per nilai. Beberapa bahasa membedakan antara objek kelas dan struct (atau sejenisnya), dan mungkin memiliki perilaku yang berbeda untuk meneruskan variabel dari tipe yang berbeda. Tetapi JavaScript tidak melakukan hal seperti ini secara otomatis ketika melewati variabel objek. Tetapi tidak adanya kloning objek otomatis tidak diterjemahkan menjadi pass-by-reference.
sumber
JavaScript melewati tipe primitif berdasarkan nilai dan tipe objek dengan referensi
- Brian Bi - Bahasa pemrograman manakah yang dilewati oleh referensi?
Memperbarui
Inilah bantahan untuk ini:
Tidak ada "pass by reference" yang tersedia di JavaScript.
sumber
Cara sederhana saya untuk memahami ini ...
Saat memanggil fungsi, Anda mengirimkan konten (referensi atau nilai) dari variabel argumen, bukan variabel itu sendiri.
Di dalam fungsi, variabel parameter,
inVar1
daninVar2
, menerima konten yang diteruskan.Sejak
inVar2
menerima referensi{ prop: 2 }
, Anda dapat mengubah nilai properti objek.sumber
Melewati argumen ke fungsi dalam JavaScript analog dengan melewati parameter dengan nilai pointer di C:
sumber
Untuk pengacara bahasa pemrograman, saya telah membaca bagian ECMAScript 5.1 berikut ini (yang lebih mudah dibaca daripada edisi terakhir), dan menanyakannya di milis ECMAScript.
TL; DR : Everythings're dilewati oleh nilai, tetapi properti dari Objects adalah referensi, dan definisi Object sangat kurang dalam standar.
Konstruksi Daftar Argumen
Bagian 11.2.4 "Daftar Argumen" mengatakan yang berikut tentang membuat daftar argumen yang hanya terdiri dari 1 argumen:
Bagian ini juga menyebutkan kasus di mana daftar argumen memiliki 0 atau> 1 argumen.
Dengan demikian, semuanya dilewatkan dengan referensi.
Akses Properti Obyek
Bagian 11.2.1 "Aksesor Properti"
Dengan demikian, properti Objek selalu tersedia sebagai referensi.
Tentang Referensi
Dijelaskan di bagian 8.7 "Tipe Spesifikasi Referensi", bahwa referensi tersebut bukan tipe nyata dalam bahasa - mereka hanya digunakan untuk menggambarkan perilaku dari delete, typeof, dan operator penugasan.
Definisi "Objek"
Didefinisikan dalam edisi 5.1 bahwa "Objek adalah kumpulan properti". Oleh karena itu, kita dapat menyimpulkan, bahwa nilai objek adalah koleksi, tetapi untuk apa nilai koleksi tidak didefinisikan dengan jelas dalam spesifikasi, dan memerlukan sedikit usaha untuk memahami.
sumber
Dokumen MDN menjelaskannya dengan jelas, tanpa terlalu bertele-tele:
Sumber: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Description
sumber
Dalam bahasa tingkat rendah, jika Anda ingin melewatkan variabel dengan referensi, Anda harus menggunakan sintaks tertentu dalam pembuatan fungsi:
The
&age
adalah referensi kemyAge
, tetapi jika Anda ingin nilai Anda harus mengkonversi referensi, menggunakan*age
.Javascript adalah bahasa tingkat tinggi yang melakukan konversi ini untuk Anda. Jadi, meskipun objek dilewatkan oleh referensi, bahasa mengubah parameter referensi ke nilai. Anda tidak perlu menggunakan
&
, pada definisi fungsi, untuk meneruskannya dengan referensi, juga*
, pada badan fungsi, untuk mengkonversi referensi ke nilai, JS melakukannya untuk Anda.Itu sebabnya ketika Anda mencoba mengubah objek di dalam suatu fungsi, dengan mengganti nilainya (yaitu
age = {value:5}
), perubahan itu tidak berlanjut, tetapi jika Anda mengubah sifatnya (yaituage.value = 5
), itu akan terjadi.Belajarlah lagi
sumber
Saya sudah membaca jawaban ini beberapa kali, tetapi tidak BENAR-BENAR mendapatkannya sampai saya belajar tentang definisi teknis "Panggilan dengan berbagi" seperti yang disebut oleh Barbara Liskov
Artinya, referensi parameter dapat diubah jika Anda pergi dan mengakses nilai parameter itu sendiri. Di sisi lain, penugasan ke parameter akan hilang setelah evaluasi, dan tidak dapat diakses oleh pemanggil fungsi.
sumber
Cara yang paling sederhana
sumber
JSON.parse( JSON.stringify( obj ) )
adalah cara yang mengerikan untuk mengkloning objek. Tidak hanya itu tidak hanya lambat, tetapi juga dapat menyebabkan kehilangan data.Saya telah menemukan metode perluasan dari perpustakaan Underscore.js sangat berguna ketika saya ingin mengirimkan objek sebagai parameter yang dapat dimodifikasi atau diganti seluruhnya.
sumber
Penjelasan paling ringkas yang saya temukan ada di panduan gaya AirBNB :
Primitif : Ketika Anda mengakses tipe primitif, Anda bekerja langsung pada nilainya
Misalnya:
Kompleks : Ketika Anda mengakses tipe kompleks Anda bekerja pada referensi nilainya
Misalnya:
Yaitu tipe primitif secara efektif dilewatkan oleh nilai, dan tipe kompleks dilewatkan oleh referensi.
sumber
Saya akan mengatakan itu pass-by-copy -
Pertimbangkan argumen dan objek variabel adalah objek yang dibuat selama konteks eksekusi yang dibuat di awal pemanggilan fungsi - dan nilai / referensi Anda yang sebenarnya diteruskan ke fungsi, simpan saja dalam argumen ini + objek variabel.
Secara sederhana, untuk tipe primitif, nilai-nilai disalin di awal pemanggilan fungsi, untuk tipe objek, referensi disalin.
sumber
Ada beberapa diskusi tentang penggunaan istilah "pass by reference" di JavaScript di sini , tetapi untuk menjawab pertanyaan Anda:
(Dari artikel yang disebutkan di atas.)
sumber
Cara mudah untuk menentukan apakah sesuatu itu "lewat referensi" adalah apakah Anda bisa menulis fungsi "tukar". Misalnya, dalam C, Anda dapat melakukan:
Jika Anda tidak dapat melakukan yang setara dengan itu di JavaScript, itu bukan "lewat referensi".
sumber
Array dan Object dilewatkan sebagai pass by reference atau pass by value berdasarkan kedua kondisi ini.
jika Anda mengubah nilai Objek atau array dengan Objek atau Array baru, maka nilai tersebut diteruskan oleh Value.
object1 = {item: "car"}; array1=[1,2,3];
di sini Anda menugaskan objek atau array baru ke yang lama. Anda tidak mengubah nilai properti dari objek lama.
jika Anda mengubah nilai properti dari suatu objek atau array maka itu dilewatkan oleh Referensi.
object1.key1= "car"; array1[0]=9;
di sini Anda mengubah nilai properti objek lama. Anda tidak menetapkan objek atau array baru ke yang lama.
Kode
sumber
sumber
Nilai-nilai sederhana di dalam fungsi tidak akan mengubah nilai-nilai di luar fungsi (mereka dilewatkan oleh nilai), sedangkan yang kompleks akan (mereka dilewatkan oleh referensi).
sumber