Kata Pengantar
Ayat dalam tajuk artikel ini pada asalnya dilihat dalam spesifikasi JavaScript asing Pada masa itu, ia tidak menarik perhatian yang mencukupi sehingga pepijat baru-baru ini menemui ciri-ciri (perangkap) operasi penugasan berterusan dalam JS.
Selepas mencari dalam talian, saya menemui contoh tugasan berterusan yang sangat baik (sumber 1, sumber 2):
var a = {n:1}; a.x = a = {n:2}; console.log(a.x); // 输出?
Jawapannya ialah:
console.log(a.x); // undefined
Saya tidak tahu sama ada anda mendapat jawapan yang betul, sekurang-kurangnya saya salah.
Jadi saya mengambil peluang ini untuk melihat dengan lebih dekat cara tugasan berterusan JS berfungsi
Pesanan tugasan?
Andaikan terdapat kod: A=B=C , susunan pelaksanaan pernyataan tugasan adalah dari kanan ke kiri, jadi masalahnya ialah:
Adakah andaian 1: B = C;
Atau teka 2: B = C;
Kita semua tahu bahawa jika dua objek menghala ke objek pada masa yang sama, maka pengubahsuaian kepada objek ini disegerakkan, seperti:
var a={n:1}; var b=a; a.n=2; console.log(b);//Object {n: 2}
Jadi, anda boleh menguji susunan tugasan berturut-turut berdasarkan ciri ini.
Mengikut tekaan 1, gantikan C dengan objek tertentu Anda boleh melihat bahawa pengubahsuaian a tidak akan disegerakkan kepada b, kerana dua {n:1} dibuat apabila baris pertama dan kedua dilaksanakan. Seperti:
var b={n:1}; var a={n:1}; a.n=0; console.log(b);//Object {n: 1}
Mengikut tekaan 2, gantikan C dengan objek tertentu Anda boleh melihat bahawa pengubahsuaian a disegerakkan kepada b, kerana a dan b merujuk kepada objek pada masa yang sama, seperti:
.var b={n:1}; var a=b; a.n=0; console.log(b);//Object {n: 0}
Menguji tugasan berterusan yang benar:
var a,b; a=b={n:1}; a.n=0; console.log(b);//Object {n: 0}
Anda dapat melihat bahawa ia konsisten dengan tekaan 2. Jika sesiapa merasakan ujian ini tidak tepat, anda boleh mengujinya semula dan menggunakan ciri penetap dan pengambil ECMA5 untuk menguji.
Pertama sekali, setter dan getter digunakan pada nama pembolehubah, bukan objek yang sebenarnya disimpan dalam pembolehubah, seperti berikut:
Object.defineProperty(window,"obj",{ get:function(){ console.log("getter!!!"); } }); var x=obj; obj;//getter!!! undefined x;//undefined
Anda dapat melihat bahawa hanya obj mengeluarkan "pengambil!!!", tetapi x tidak menggunakan ciri ini untuk menguji.
Ujian tugasan berterusan 2:
Object.defineProperty(window,"obj",{ get:function(){ console.log("getter!!!"); } }); a=b=obj;//getter!!! undefined
Disahkan sekali lagi melalui pengambil, dalam A=B=C, C hanya dibaca sekali.
Jadi, peraturan operasi sebenar penetapan berterusan ialah B = C A = B, iaitu, penetapan berterusan sentiasa mengambil hanya hasil ungkapan di sebelah kanan tanda sama dari kanan ke kiri dan menetapkannya ke kiri; sisi tanda sama.
Bolehkah tugasan berterusan ditulis secara berasingan?
Anda boleh melihat peraturan sebenar tugasan berterusan daripada di atas Kemudian kembali ke kes pada permulaan artikel Jika anda membahagikan tugasan berterusan mengikut peraturan di atas, anda akan mendapati bahawa hasilnya adalah berbeza sebagai:
var a={n:1}; a={n:2}; a.x=a; console.log(a.x);//Object {n: 2, x: Object}
Jadi, walaupun penyataan tugasan berterusan mengikut peraturan tugasan dari kanan ke kiri, ia masih tidak boleh ditulis dalam penyataan berasingan Adapun mengapa
Saya rasa: Untuk memastikan ketepatan pernyataan tugasan, js akan terlebih dahulu mengeluarkan salinan semua alamat rujukan yang akan diberikan sebelum melaksanakan pernyataan tugasan, dan kemudian memberikan nilai satu demi satu.
Jadi saya rasa logik kod ini a.x=a={n:2};
1. Sebelum pelaksanaan, alamat rujukan a dalam a dan a.x akan dikeluarkan terlebih dahulu2. Cipta objek baharu {n:2} dalam ingatan
3. Laksanakan a={n:2} dan tukar rujukan a daripada menunjuk ke {n:1} kepada menunjuk ke {n:2}
baharu4. Laksanakan a.x=a pada masa ini, a sudah menunjuk ke objek baharu, dan kerana a.x mengekalkan rujukan asal sebelum pelaksanaan, a.x a menunjuk ke objek {n:1} asal, jadi objek baharu diberikan kepada objek asal Tambahkan atribut x dengan kandungan {n:2}, yang kini menjadi
5. Pelaksanaan pernyataan tamat, objek asal berubah daripada {n:1} kepada {n:1,x:{n:2}}, dan objek asal dikitar semula oleh GC kerana tiada siapa yang merujuknya lagi. Pada masa ini Titik ke objek baharu {n:2}
6. Jadi, kami mempunyai hasil larian pada permulaan artikel, dan kemudian jalankan a.x, ia secara semula jadi tidak ditentukan
Proses di atas digambarkan dengan nombor siri:
Berikutan proses di atas, dapat dilihat bahawa a.x lama dan a baharu kedua-duanya menghala ke objek yang baru dibuat {n:2}, jadi ia sepatutnya kongruen.
Ujian:
Oleh kerana kami menambah var b=a, yang bermaksud menambah rujukan kepada objek asal, ia tidak akan dikeluarkan dalam langkah 5 di atas, yang mengesahkan kesimpulan di atas.
Posskrip
Melalui masa ini, saya belajar tentang ciri-ciri tugasan berterusan. Melihat kembali tajuk artikel, nampaknya ia harus dipanggil:
Cuba untuk tidak menggunakan operasi penugasan berterusan JS melainkan anda benar-benar memahami mekanisme dalaman dan kemungkinan akibatnya.