Rumah > Artikel > hujung hadapan web > Padamkan kunci di tengah-tengah pengetahuan Javascript Object_Basic
Anda juga tidak boleh melakukan ini, pulang ke rumah dan bertani
Dengan cara ini, mari kita bercakap tentang cara menggunakan padam
Beberapa minggu yang lalu, saya berpeluang melihat buku Stoyan Stefanov Object-Oriented Javascript Buku ini mempunyai penarafan tinggi di Amazon (12 ulasan, 5 bintang), jadi saya ingin tahu sama ada ia seperti itu. buku yang disyorkan, saya mula membaca bab tentang fungsi. Saya sangat menyukai cara buku ini menerangkan perkara, dan contoh-contohnya disusun dengan cara yang sangat bagus dan progresif pengetahuan dengan mudah Walau bagaimanapun, hampir serta-merta, saya menemui salah faham yang menarik yang berulang sepanjang bab - memadamkan fungsi fungsi Terdapat juga beberapa ralat lain (seperti pengisytiharan fungsi dan ungkapan fungsi), tetapi kami tidak akan membincangkannya buat masa ini. .
Buku ini mendakwa:
"Sesuatu fungsi dianggap seperti pembolehubah biasa - ia boleh disalin ke pembolehubah lain atau dipadamkan".
Jadi, apakah sebenarnya yang berlaku dalam contoh ini? Adakah ia satu pepijat Atau adakah ia adalah penggunaan khas Mungkin bukan kod ini sebenarnya dalam konsol Firebug, dan Stoyan mesti menggunakannya sebagai alat ujian pantas. Ia hampir seolah-olah Firebug mematuhi beberapa peraturan pemadaman yang lain yang menyebabkan Stoyan sesat
Sebelum menjawab soalan ini, kami terlebih dahulu perlu memahami cara pengendali padam berfungsi dalam JavaScript: Apa yang boleh dipadamkan dan apa yang tidak boleh dipadamkan Hari ini, saya akan cuba menerangkan soalan ini secara terperinci Tingkah laku "pelik" dan menyedari bahawa ia tidak begitu pelik selepas semua Keserasian penyemak imbas dan beberapa pepijat yang paling terkenal Kami juga akan membincangkan mod ketat ES5 dan cara ia mengubah tingkah laku pengendali padam.
Saya akan menggunakan JavaScript dan ECMAScript secara bergantian, kedua-duanya bermaksud ECMAScript (melainkan jelas bercakap tentang pelaksanaan JavaScript Mozilla)
Tidak menghairankan, penjelasan mengenai pemadaman agak terhad di web Artikel MDC mungkin merupakan sumber terbaik untuk difahami, tetapi, malangnya, ia kehilangan beberapa butiran menarik mengenai perkara itu. Ya, salah satu perkara yang terlupa bertanggungjawab untuk tingkah laku pelik Firebug Dan rujukan MSDN hampir tidak berguna dalam aspek ini
TeoriJadi, mengapa kita boleh memadamkan sifat objek:
Nota: Apabila atribut tidak boleh dipadamkan, operator padam hanya akan mengembalikan palsu
Untuk memahami perkara ini, pertama sekali kita perlu memahami konsep ini tentang contoh pembolehubah dan sifat sifat - konsep yang, malangnya, jarang disebut dalam buku JavaScript, saya akan cuba menerangkannya dalam beberapa perenggan seterusnya Tinjau secara ringkas konsep ini konsep sukar difahami! Jika anda tidak mengambil berat tentang "mengapa perkara ini berfungsi dengan cara yang betul", sila langkau bab ini
Jenis kod:Dalam ECMAScript, terdapat 3 jenis kod boleh laku yang berbeza: Kod global, Kod fungsi dan kod Eval Jenis ini lebih kurang sama dalam nama, berikut ialah gambaran ringkas:
Apabila sekeping kod sumber dilihat sebagai program, ia akan dilaksanakan dalam persekitaran global dan dianggap kod global Dalam persekitaran penyemak imbas, kandungan elemen skrip biasanya Ditafsirkan sebagai program dan oleh itu dilaksanakan sebagai global kod.
Sebarang kod yang dilaksanakan secara langsung dalam fungsi jelas dianggap kod fungsi Dalam penyemak imbas, kandungan atribut acara (seperti
) biasanya Ditafsirkan ke dalam kod fungsi.
Akhir sekali, teks kod yang digunakan pada fungsi eval terbina dalam ditafsirkan sebagai kod Eval Tidak lama lagi kita akan mengetahui sebab jenis ini istimewa.
Konteks pelaksanaan:
Apabila kod ECMAScript dilaksanakan, ia biasanya berlaku dalam konteks pelaksanaan khusus ialah konsep entiti yang agak abstrak yang membantu memahami cara skop (Skop) dan instantiasi berubah (Instasiasi Pembolehubah) berfungsi kod boleh laku, terdapat konteks pelaksanaan yang sepadan dengannya Apabila fungsi dilaksanakan, kita katakan bahawa "kawalan program memasuki konteks pelaksanaan kod fungsi"; apabila sekeping kod global dilaksanakan, Kawalan program memasuki konteks pelaksanaan kod global, dsb.
Seperti yang anda lihat, konteks pelaksanaan secara logiknya boleh membentuk timbunan Pertama, mungkin terdapat sekeping kod global dengan konteks pelaksanaannya sendiri, dan kemudian sekeping kod itu mungkin memanggil fungsi, mengambilnya dengan konteks pelaksanaan . Fungsi ini boleh memanggil fungsi lain, dsb. Walaupun fungsi itu dipanggil secara rekursif, ia akan memasuki konteks pelaksanaan baharu setiap kali ia dipanggil
Objek pengaktifan/Objek Pembolehubah:
Setiap konteks pelaksanaan mempunyai objek yang dipanggil pembolehubah yang dikaitkan dengannya Sama seperti konteks pelaksanaan, objek pembolehubah ialah entiti abstrak, mekanisme yang digunakan untuk menerangkan kejadian pembolehubah Perkara yang menarik ialah, Pembolehubah dan fungsi yang diisytiharkan dalam kod sumber biasanya ditambahkan pada objek pembolehubah ini sebagai sifat
Apabila kawalan program memasuki konteks pelaksanaan kod global, objek global digunakan sebagai objek berubah Inilah sebabnya pembolehubah fungsi yang diisytiharkan sebagai global menjadi sifat objek global.
foo === GLOBAL_OBJECT.foo; // benar
bar fungsi(){}
GLOBAL_OBJECT.bar === bar; // true
Bukan sahaja pembolehubah dan fungsi yang diisytiharkan dalam kod fungsi akan menjadi sifat objek aktif ini juga akan dilakukan dalam setiap parameter fungsi (bersamaan dengan nama parameter formal yang sepadan) dan objek Argumen khas (dengan argumen; sebagai nama). Harap maklum bahawa objek aktif ialah mekanisme penerangan dalaman dan tidak boleh diakses daripada kod program
Sekarang kita mempunyai idea yang jelas tentang perkara yang berlaku kepada pembolehubah (ia menjadi sifat), satu-satunya konsep yang perlu difahami ialah atribut sifat Setiap Sifat boleh mempunyai sifar atau lebih atribut, dipilih daripada set berikut: ReadOnly, DontEnum, DontDelete dan Internal Anda boleh menganggapnya sebagai bendera - atribut mungkin ada atau mungkin tidak ada dalam atribut Bagi kami Untuk perbincangan hari ini, kami hanya berminat dengan DontDelete.
Apabila pembolehubah dan fungsi yang diisytiharkan menjadi atribut objek pembolehubah (atau objek aktif kod fungsi, atau objek global kod global), atribut ini dicipta dengan atribut DontDelete Walau bagaimanapun, sebarang Sifat eksplisit dicipta oleh (atau tersirat) penetapan sifat tidak akan mempunyai atribut DontDelete Inilah sebabnya kami boleh memadamkan beberapa sifat, tetapi bukan yang lain
Jadi, ini semua tentangnya (DontDelete): atribut khas atribut, digunakan untuk mengawal sama ada atribut ini boleh dipadamkan. Sila ambil perhatian bahawa beberapa atribut objek terbina dalam ditentukan untuk mengandungi DontDelete, jadi ia tidak boleh dipadamkan . Contohnya Pembolehubah argumen khas (atau, seperti yang kita ketahui, sifat objek aktif) mempunyai sifat DontDelete
Atribut yang sepadan dengan parameter fungsi juga mempunyai atribut DontDelete sejak penciptaannya, jadi kami tidak boleh memadamkannya.
Tugasan tidak diisytiharkan:
Anda mungkin ingat bahawa tugasan yang tidak diisytiharkan mencipta sifat pada objek global, melainkan harta itu sudah ditemui di tempat lain dalam rantaian skop sebelum objek global Dan, kini kita tahu tentang penetapan harta dan pembolehubah Perbezaan antara pengisytiharan - yang terakhir akan menetapkan sifat DontDelete, tetapi yang pertama tidak
Apa yang berlaku dalam Firebug? Mengapa pembolehubah yang diisytiharkan dalam konsol boleh dipadamkan? Pembolehubah yang diisytiharkan dalam Eval sebenarnya dicipta sebagai sifat tanpa atribut DontDelete.
foo; // 1
padam foo; // benar
jenis foo; // "tidak ditentukan"
Padamkan pembolehubah melalui Eval:
Tingkah laku eval yang menarik ini, ditambah dengan satu lagi aspek ECMAScript, secara teknikal boleh membenarkan kami mengalih keluar atribut "tidak boleh padam" Perkara mengenai pengisytiharan fungsi ialah ia boleh mengatasi pembolehubah dengan nama yang sama dalam konteks pelaksanaan yang sama.
Perhatikan cara pengisytiharan fungsi diutamakan dan mengatasi pembolehubah dengan nama yang sama (atau, dalam erti kata lain, sifat yang sama dalam objek pembolehubah Ini kerana pengisytiharan fungsi dibuat seketika selepas perisytiharan pembolehubah, dan dibenarkan). Mengatasinya (pengisytiharan pembolehubah) bukan sahaja menggantikan nilai harta, ia juga menggantikan atribut harta itu Jika kita mengisytiharkan fungsi melalui eval, fungsi itu harus menggantikannya dengan atribut asal (digantikan) juga, memandangkan pembolehubah yang diisytiharkan melalui eval mencipta sifat tanpa atribut DontDelete, membuat instantiating fungsi baharu ini sebenarnya akan mengalih keluar atribut DontDelete yang sedia ada daripada atribut, sekali gus menjadikan sifat A boleh dipadamkan (dan, jelas sekali, menunjukkan nilainya kepada fungsi yang baru dicipta).
Malangnya, "penipu" ini tidak berfungsi dalam mana-mana pelaksanaan semasa Mungkin saya kehilangan sesuatu di sini, atau tingkah lakunya sangat kabur sehingga pelaksana tidak menyedarinya.
Keserasian pelayar:
Memahami cara perkara berfungsi secara teori adalah berguna, tetapi amalan adalah yang paling penting Adakah penyemak imbas mengikut piawaian apabila ia berkaitan dengan penciptaan/pemadaman pembolehubah/sifat Jawapannya ialah: Dalam kebanyakan kes, ya.
Saya menulis set ujian ringkas untuk menguji keserasian penyemak imbas dengan pengendali padam, termasuk ujian di bawah kod global, kod fungsi dan kod Eval Set ujian menyemak nilai pulangan dan nilai atribut pengendali padam sama ada (seperti yang sepatutnya ) benar-benar dipadamkan. Nilai pulangan padam tidak sepenting hasil sebenar. Tidak penting jika padam mengembalikan benar dan bukannya palsu, yang penting ialah mereka yang mempunyai atribut DontDelete tidak dipadamkan. dan sebaliknya.
Pelayar moden secara amnya agak serasi Kecuali untuk ciri eval yang saya nyatakan sebelum ini, penyemak imbas berikut melepasi semua set ujian: Opera 7.54, Firefox 1.0, Safari 3.1.2, Chrome 4.
Safari 2.x dan 3.0.4 menghadapi masalah memadamkan parameter fungsi; sifat ini nampaknya dicipta tanpa DontDelete, jadi mereka boleh dipadamkan Safari 2.x mempunyai lebih banyak masalah - memadam pembolehubah jenis bukan rujukan (cth: padam 1) akan membuang pengecualian; pengisytiharan fungsi akan mencipta sifat boleh dipadam (tetapi, peliknya, pengisytiharan pembolehubah tidak akan menjadi tidak boleh dipadam (tetapi pengisytiharan fungsi tidak akan dipadam).
Sama seperti Safari, Konqueror (3.5, bukan 4.3) akan membuang pengecualian apabila memadamkan jenis bukan rujukan (seperti: padam 1), dan tersilap menjadikan pembolehubah fungsi boleh dipadam.
Nota Penterjemah:
Saya menguji versi terbaharu chrome, firefox dan IE, dan pada asasnya mengekalkan pas kecuali 23 dan 24, yang gagal saya juga menguji UC dan beberapa penyemak imbas mudah alih, sebagai tambahan kepada penyemak imbas terbina dalam Nokia E72. Kecuali untuk Fail 15 dan 16, kebanyakan penyemak imbas terbina dalam yang lain mempunyai kesan yang sama seperti penyemak imbas desktop Tetapi perlu dinyatakan bahawa penyemak imbas terbina dalam Blackberry Curve 8310/8900 boleh melepasi ujian 23, yang mengejutkan saya.
Gecko DontDelete pepijat:
Pelayar Gecko 1.8.x - Firefox 2.x, Camino 1.x, Seamonkey 1.x, dsb. - mempamerkan pepijat yang sangat menarik, tugasan eksplisit kepada harta akan memadamkan Atribut DontDeletenya, walaupun atribut itu dicipta melalui pengisytiharan berubah-ubah atau pengisytiharan fungsi.
Anehnya, Internet Explorer 5.5 - 8 melepasi keseluruhan set ujian, kecuali memadam jenis bukan rujukan (cth: padam 1) akan memberikan pengecualian (sama seperti Safari lama Tetapi di bawah IE terdapat pepijat yang lebih serius). tidak begitu jelas. Pepijat ini berkaitan dengan objek Global.
Pepijat IE:
Keseluruhan bab ini adalah mengenai pepijat Internet Explorer Wow!
Dalam IE (sekurang-kurangnya IE 6-8), ungkapan berikut akan membuang pengecualian (apabila dilaksanakan dalam kod global):
ini.x = 1;
delete x; // TypeError: Object tidak menyokong tindakan ini
Yang ini juga, tetapi memberikan pengecualian berbeza, yang menjadikan perkara lebih menarik:
var x = 1;
delete this.x; // TypeError: Tidak boleh padam 'this.x'
Nampaknya dalam IE, pengisytiharan berubah dalam kod global tidak mencipta sifat pada objek global Mencipta harta melalui tugasan (this.x = 1) dan kemudian memadamkannya melalui padam x akan membuang ralat (var x = 1) dan kemudian padamkannya dengan memadam ini.x melemparkan ralat lain.
Tetapi bukan itu sahaja Mencipta sifat melalui tugasan eksplisit sebenarnya akan menyebabkan pengecualian dibuang pada pemadaman. Bukan sahaja terdapat ralat di sini, tetapi sifat yang dibuat nampaknya mempunyai atribut DontDelete. Patutlah.
ini.x = 1;
padam this.x; // TypeError: Object tidak menyokong tindakan ini
typeof x; // "nombor" (masih wujud, tidak dipadamkan seperti yang sepatutnya!)
padam x; // TypeError: Objek tidak menyokong tindakan ini
typeof x; // "nombor" (tidak dipadamkan lagi)
Sekarang, kami akan menganggap bahawa di bawah IE, tugasan yang tidak diisytiharkan (yang sepatutnya mencipta sifat pada objek global) sememangnya mencipta sifat boleh dipadam
x = 1;
padamkan x; // benar
jenis x; // "tidak ditentukan"
Walau bagaimanapun, jika anda memadamkan atribut ini melalui rujukan ini dalam kod global (padamkan ini.x), ralat yang serupa akan muncul.
x = 1;
delete this.x; // TypeError: Tidak boleh padam 'this.x'
Jika kita ingin menyamaratakan gelagat ini, nampaknya pemadaman pembolehubah daripada kod global menggunakan delete this.x tidak pernah berjaya Apabila sifat yang dipersoalkan dibuat melalui tugasan eksplisit (this.x = 1) delete akan menimbulkan ralat; dicipta oleh tugasan tidak diisytiharkan (x = 1) atau oleh pengisytiharan (var x = 1), padam membuang ralat lain.
padam x, sebaliknya, hanya perlu membuang ralat jika sifat itu dicipta oleh tugasan eksplisit - ini.x = 1. Jika sifat dicipta melalui pengisytiharan (var x = 1) , pemadaman tidak pernah berlaku, dan pemadaman dengan betul mengembalikan palsu Jika sifat dibuat melalui tugasan yang tidak diisytiharkan (x = 1), pemadaman berfungsi seperti yang diharapkan
Saya memikirkan isu ini sekali lagi pada bulan September, dan Garrett Smith mencadangkan bahawa di bawah IE,"Objek pembolehubah global dilaksanakan sebagai objek JScript dan objek global dilaksanakan oleh hos".
Garrett menggunakan entri blog Eric Lippert sebagai rujukan.
Kita boleh lebih kurang mengesahkan teori ini dengan melaksanakan beberapa ujian Perhatikan bahawa ini dan tetingkap kelihatan menunjuk ke objek yang sama (jika kita boleh mempercayai operator ===), tetapi objek berubah (pengisytiharan fungsi Objek di mana. ia terletak) berbeza daripada yang ditunjukkan oleh ini.
window.getBase() === this.getBase(); // true
window.getBase() === getBase(); // false
Salah Faham:
Keindahan memahami mengapa perkara berfungsi seperti yang mereka lakukan tidak boleh diremehkan Saya telah melihat beberapa salah tanggapan tentang pengendali padam di seluruh web Sebagai contoh, jawapan ini pada Stackoverflow (dengan rating yang mengejutkan tinggi), jelas Confidence
"Apabila operan sasaran bukan harta objek, padam hendaklah menjadi no-op".
Sekarang kita memahami teras kelakuan operasi padam, ralat jawapan ini menjadi jelas padam tidak membezakan antara pembolehubah dan sifat (sebenarnya, untuk pemadaman, kedua-duanya adalah jenis rujukan ) dan sebenarnya hanya mengambil berat tentang DontDelete. atribut (dan sama ada atribut itu sendiri wujud).
Ia juga sangat menarik untuk melihat pelbagai salah tanggapan yang dibalas oleh satu sama lain, dalam urutan yang sama, seorang mula-mula mencadangkan hanya memadamkan pembolehubah (yang tidak akan memberi kesan melainkan ia diisytiharkan dalam eval), manakala seorang lagi Memberi pembetulan pepijat menerangkan cara pemadaman boleh digunakan untuk memadam pembolehubah dalam kod global, tetapi bukan dalam kod fungsi
Berhati-hati dengan tafsiran JavaScript di Internet, pendekatan yang ideal adalah untuk sentiasa memahami sifat masalah ;)padam dan Hos Objek:
Algoritma pemadaman adalah kira-kira seperti berikut:
Jika operan bukan jenis rujukan, kembalikan benar
Jika objek tidak mempunyai sifat langsung dengan nama ini, mengembalikan benar (seperti yang kita tahu, objek itu boleh menjadi objek aktif atau objek global)
Jika harta itu wujud tetapi mempunyai atribut DontDelete, kembalikan false
Dalam kes lain, padamkan atribut dan kembalikan benar
Walau bagaimanapun, kelakuan pengendali padam pada objek hos tidak dapat diramalkan Dan sebenarnya tidak ada yang salah dengan tingkah laku ini: (mengikut standard), objek hos dibenarkan untuk melaksanakan fungsi seperti baca (dalaman [[Dapatkan]]), tulis. (kaedah [[Put]] dalaman) dan padam (kaedah [[Padam]] dalaman) beberapa pengendali melaksanakan sebarang gelagat ini untuk tingkah laku tersuai [[Padam]] yang mengubah objek hos kepada Punca kekeliruan.
typeof window.alert; // "fungsi"
Moral cerita ini ialah: Jangan sekali-kali mempercayai objek hos.
Mod ketat ES5:
Jadi, apakah yang dibawa oleh mod ketat ECMAScript 5 kepada kita. Ia memperkenalkan sangat sedikit ralat sintaks apabila ungkapan pengendali padam adalah rujukan langsung kepada pembolehubah, parameter fungsi atau pengecam fungsi akan dilemparkan , jika harta tersebut mempunyai atribut dalaman [[Configurable]] == false, ralat jenis akan dilemparkan.
Selain itu, memadamkan pembolehubah yang tidak diisytiharkan (atau rujukan yang tidak dapat diselesaikan) juga akan menimbulkan ralat sintaks:
"gunakan ketat";
padamkan i_dont_exist; // SyntaxError
Tugasan yang tidak diisytiharkan berkelakuan serupa dengan pembolehubah yang tidak diisytiharkan dalam mod ketat (kecuali kali ini ia menimbulkan ralat rujukan dan bukannya ralat sintaks):
"gunakan ketat";
i_dont_exist = 1; // ReferenceError
Seperti yang anda faham sekarang, semua sekatan lebih kurang masuk akal, kerana pemadaman pembolehubah, pengisytiharan fungsi dan parameter menyebabkan banyak kekeliruan daripada mengabaikan pemadaman secara senyap, mod ketat mengambil langkah yang lebih agresif dan lebih Deskriptif.
Ringkasan:
Catatan blog ini akhirnya menjadi agak panjang, jadi saya tidak akan bercakap tentang perkara seperti memadamkan objek tatasusunan dengan pemadaman atau maksudnya Anda boleh merujuk artikel MDC untuk penjelasan khusus (atau membaca standard dan Lakukan eksperimen anda sendiri).
Berikut ialah ringkasan ringkas tentang cara pemadaman berfungsi dalam JavaScript:
Pengisytiharan pembolehubah dan fungsi ialah sifat objek aktif atau objek global
Atribut mempunyai beberapa ciri, antaranya DontDelete ialah ciri yang menentukan sama ada atribut boleh dipadamkan
Pengisytiharan pembolehubah dan fungsi dalam kod global atau berfungsi sentiasa mencipta sifat dengan atribut DontDelete.
Parameter fungsi sentiasa sifat objek aktif dan mempunyai DontDelete.
Pembolehubah dan fungsi yang diisytiharkan dalam kod Eval sentiasa dibuat tanpa sifat DontDelete
Sifat baharu tidak mempunyai atribut apabila ia dicipta (dan sudah tentu tiada DontDelete
).
Objek hos dibenarkan untuk memutuskan cara bertindak balas terhadap operasi pemadaman.
Jika anda ingin lebih mengenali perkara yang diterangkan di sini, sila rujuk spesifikasi ECMA-262 edisi ke-3.
Saya harap anda menikmati artikel ini dan mempelajari sesuatu yang baharu. Sebarang pertanyaan, cadangan atau pembetulan dialu-alukan.