Rumah >hujung hadapan web >tutorial js >Pemahaman mendalam tentang mekanisme asas JS seperti jenis data JS, prapenyusun dan konteks pelaksanaan

Pemahaman mendalam tentang mekanisme asas JS seperti jenis data JS, prapenyusun dan konteks pelaksanaan

WBOY
WBOYke hadapan
2021-12-27 18:48:522454semak imbas

JavaScript terdiri daripada tiga bahagian: Model Objek Dokumen DOM, Model Objek Pelayar BOM dan teras ECMAScript Artikel ini membawa pengetahuan tentang prinsip asas dalam JavaScript dan berharap dapat membantu semua orang.

Pemahaman mendalam tentang mekanisme asas JS seperti jenis data JS, prapenyusun dan konteks pelaksanaan

JavaScript ialah bahasa pentafsiran literal yang dinamik, ditaip lemah dan berasaskan prototaip. JavaScript berakar umbi dalam penyemak imbas web yang kami gunakan, dan penterjemahnya ialah enjin JavaScript dalam penyemak imbas. Bahasa skrip yang digunakan secara meluas di bahagian klien ini mula-mula digunakan untuk mengendalikan beberapa operasi pengesahan input yang sebelum ini dikendalikan oleh bahasa bahagian pelayan Dengan perkembangan era Web, JavaScript terus berkembang dan menjadi bahasa pengaturcaraan yang berfungsi sepenuhnya . Penggunaannya tidak lagi terhad kepada pengesahan data mudah, tetapi mempunyai keupayaan untuk berinteraksi dengan hampir semua aspek tetingkap penyemak imbas dan kandungannya. Ia adalah bahasa yang sangat mudah dan bahasa yang sangat kompleks Jika kita ingin benar-benar mahir dalam JavaScript, kita mesti mempunyai pemahaman yang mendalam tentang beberapa prinsip reka bentuk asasnya. Artikel ini akan merujuk kepada siri buku "Pengaturcaraan Lanjutan JavaScript" dan "JS Anda Tidak Tahu" untuk menerangkan beberapa pengetahuan asas tentang JavaScript.

Jenis data

Mengikut kaedah penyimpanan, jenis data JavaScript boleh dibahagikan kepada dua Dua jenis, jenis data primitif (nilai primitif) dan jenis data rujukan (nilai rujukan).

Pada masa ini terdapat enam jenis data primitif, termasuk Number, String, Boolean, Null, Undefined dan Symbol (ES6) Jenis ini adalah nilai sebenar yang disimpan dalam pembolehubah yang boleh dimanipulasi secara langsung. Jenis data primitif disimpan pada tindanan, dan saiz data ditentukan Ia disimpan secara langsung mengikut nilai, supaya ia boleh diakses secara langsung mengikut nilai.

Jenis data rujukan ialah Objek Dalam JavaScript, segala-galanya kecuali jenis data primitif ialah jenis Objek, termasuk tatasusunan, fungsi, ungkapan biasa, dll., yang kesemuanya merupakan objek. Jenis rujukan ialah objek yang disimpan dalam ingatan timbunan, dan pembolehubah ialah alamat rujukan yang disimpan dalam ingatan tindanan yang menunjuk ke objek dalam ingatan timbunan. Apabila pembolehubah ditakrifkan dan dimulakan kepada nilai rujukan, jika ia ditugaskan kepada pembolehubah lain, kedua-dua pembolehubah menyimpan alamat yang sama dan menghala ke ruang memori yang sama dalam memori timbunan. Jika anda mengubah suai nilai jenis data rujukan melalui salah satu pembolehubah, pembolehubah lain juga akan berubah dengan sewajarnya.

Untuk jenis data primitif, kecuali null, yang istimewa (null akan dianggap sebagai rujukan objek kosong), yang lain boleh kita gunakan typeof untuk menilai dengan tepat:

Ekspresi

Nilai pulangan

jenis 123

'nombor'

jenis "abc"

'string'

jenis benar

'boolean'

jenis null

'objek'

jenis undefined

'undefined'

jenis Pembolehubah tidak diketahui(Pembolehubah tidak ditentukan)

'tidak ditentukan'

jenis Simbol()

'simbol'

jenis fungsi() {}

'fungsi'

jenis {}

'objek'

jenis []

'objek'

jenis(/[0-9,a-z]/)

'objek'

Untuk jenis null, anda boleh menggunakan operator kongruen Buat pertimbangan. Nilai pembolehubah yang diisytiharkan tetapi tidak dimulakan akan ditetapkan tidak ditentukan secara lalai ( juga boleh ditetapkan tidak ditentukan secara manual) , dalam JavaScript, gunakan The pengendali kesamarataan == tidak dapat membezakan antara null dan undefined, dan ECMA-262 menetapkan bahawa ujian kesamaan mereka mesti kembali benar. Untuk membezakan dua nilai dengan tepat, anda perlu menggunakan operator kongruen ===.

Untuk jenis data rujukan, kecuali fungsi, yang mempunyai reka bentuk kaedah khas dan boleh dinilai dengan tepat dengan typeof, semua yang lain mengembalikan jenis objek. Kita boleh menggunakan instanceof untuk menilai nilai jenis rujukan. instanceof akan mengesan sama ada objek A adalah contoh objek lain B. Di peringkat bawah, ia akan menyemak sama ada objek B wujud pada rantai prototaip objek A ( Instance dan rantai prototaip akan dibincangkan kemudian dalam artikel). Mengembalikan benar jika ada, salah jika tidak hadir.

表达式

返回值

[1,2,3]  instanceof  Array

‘true’

function foo(){ }  instanceof  Function

‘true’

/[0-9,a-z]/  instanceof  RegExp

‘true’

new Date()  instanceof  Date

‘true’

{name:”Alan”,age:”22”}  instanceof  Object

‘true’

EkspresiNilai pulangan [1,2,3] instanceof Array'benar' function foo(){ } instanceof Function'true' /[0-9,a-z]/ instanceof RegExp'benar' tarikh Tarikh() baharu bagi Tarikh'benar'{nama:”Alan”,umur:”22”} contoh Objek ' benar'

Memandangkan semua nilai jenis rujukan adalah contoh Objek, gunakan pengendali contoh untuk menilai mereka sebagai Objek, dan hasilnya juga akan kembali benar.

Ekspresi

表达式

返回值

[1,2,3]  instanceof  Object

‘true’

function foo(){ }  instanceof  Object

‘true’

/[0-9,a-z]/  instanceof  Object

‘true’

new Date()  instanceof  Object

‘true’

Nilai pulangan

[1,2,3] instanceof Objek

'true'

function foo(){ } instanceof Object

'true'

/[0-9,a-z]/ instanceof Objek td >

'true'

new Date() instanceof Object

'true'

Sudah tentu, terdapat kaedah yang lebih berkuasa yang boleh menentukan dengan tepat sebarang jenis data dalam mana-mana JavaScript, dan itu ialah kaedah Object.prototype.toString.call(). Dalam ES5, semua objek (objek asli dan objek hos) mempunyai sifat dalaman [[Kelas]], yang nilainya ialah rentetan yang merekodkan jenis objek. Pada masa ini termasuk "Array", "Boolean", "Date", "Error", "Function", "Math", "Nombor", "Object", "RegExp", "String", "Arguments", "JSON", "Simbol". Sifat dalaman ini boleh dilihat melalui kaedah Object.prototype.toString(), tidak ada cara lain.

Apabila kaedah Object.prototype.toString() dipanggil, langkah berikut akan dilakukan: 1. Dapatkan nilai atribut [[Kelas]] objek ini ( Saya akan bercakap tentang objek ini kemudian dalam artikel) . 2. Letakkan nilai di antara dua rentetan "[objek" dan "]" dan gabungkannya. 3. Kembalikan tali yang disambung.

Apabila nilai ini adalah nol, kaedah Object.prototype.toString() secara langsung mengembalikan "[objek Null]". Apabila nilai ini tidak ditentukan, "[objek Tidak ditentukan]" dikembalikan secara langsung.

Ekspresi

Nilai pulangan

Object.prototype.toString.call(123)

[Nombor objek]

Object.prototype.toString.call("abc")

[objek String ]

Object.prototype.toString.call(true)

[objek Boolean]

Object.prototype.toString.call(null)

[objek Null]

Object.prototype.toString.call(undefined)

[object Undefined]

Object.prototype.toString.call ( Simbol())

[Simbol objek]

Object.prototype.toString.call(function foo(){})

[Fungsi objek]

Object.prototype.toString.call([1,2,3])

[object Array]

Object.prototype.toString.call({name:”Alan” })

[objek Objek]

Object.prototype.toString.call(new Date())

[Tarikh objek]

Object.prototype.toString . panggil(RegExp())

[objek RegExp]

Object.prototype.toString.call(window.JSON)

[objek JSON]

Object.prototype.toString.call(Math)

[objek Matematik]


Kaedah panggilan() boleh mengubah titik ini apabila memanggil kaedah Object.prototype.toString() supaya ia menunjuk ke objek yang kita lalui, supaya kita boleh mendapatkan atribut [[Kelas]] daripada objek yang kita lalui. (Kesan yang sama boleh dicapai menggunakan Object.prototype.toString.apply()) .

Jenis data JavaScript juga boleh ditukar Penukaran jenis data dibahagikan kepada dua kaedah: penukaran jenis eksplisit dan penukaran jenis tersirat.

Kaedah yang boleh dipanggil untuk penukaran jenis paparan termasuk Boolean(), String(), Number(), parseInt(), parseFloat() dan toString() ( null dan nilai yang tidak ditentukan tidak mempunyai kaedah ini) Penggunaan masing-masing jelas sekali imbas, jadi Saya tidak akan memperkenalkan mereka satu persatu di sini.

Memandangkan JavaScript ialah bahasa yang ditaip lemah, apabila menggunakan operator aritmetik, jenis data pada kedua-dua belah operator boleh menjadi sewenang-wenangnya, tidak seperti bahasa Java atau C Specify jenis yang sama, dan enjin secara automatik akan melakukan penukaran jenis tersirat untuk mereka. Penukaran jenis tersirat tidak seintuitif seperti penukaran jenis eksplisit Terdapat terutamanya tiga kaedah penukaran:
1. Tukar nilai kepada nilai primitif: kepadaPrimitive()

2. Tukar nilai kepada nombor: toNumber( )

3. Tukarkan nilai kepada rentetan: toString()

Secara umumnya, apabila menambah nombor dan rentetan, nombor akan ditukar menjadi rentetan apabila melakukan pertimbangan nilai kebenaran (; seperti jika, ||, &&), parameter akan ditukar kepada nilai Boolean apabila melakukan operasi perbandingan, operasi aritmetik atau operasi kenaikan dan penyusutan automatik, parameter akan ditukar kepada nilai Nombor; secara tersirat Semasa penukaran jenis, nilai pulangan kaedah toString() objek atau kaedah valueOf() akan diperolehi.

Mengenai NaN:

NaN ialah nilai berangka khas, mewakili nilai bukan angka. Pertama, sebarang operasi aritmetik yang melibatkan NaN akan mengembalikan NaN. Kedua, NaN tidak sama dengan sebarang nilai, termasuk NaN itu sendiri. ECMAScript mentakrifkan fungsi isNaN(), yang boleh digunakan untuk menguji sama ada parameter adalah "bukan angka". Ia mula-mula cuba untuk secara tersirat menukar hujah kepada nilai angka, mengembalikan benar jika ia tidak boleh ditukar kepada nilai angka.


Mula-mula kita boleh menggunakan typeof untuk menentukan sama ada ia adalah jenis Nombor, dan kemudian menggunakan isNaN untuk menentukan sama ada data semasa ialah NaN.

Mengenai rentetan:

Rentetan dalam JavaScript tidak boleh diubah Setelah rentetan dibuat, nilainya tidak boleh diubah. Untuk menukar rentetan yang dipegang oleh pembolehubah, mula-mula musnahkan rentetan asal dan kemudian isikan pembolehubah itu dengan rentetan lain yang mengandungi nilai baharu. Proses ini berlaku di latar belakang, itulah sebabnya sesetengah penyemak imbas lama sangat perlahan apabila menggabungkan rentetan.

Malah, untuk memudahkan operasi nilai jenis asas, ECMAScript juga menyediakan 3 jenis rujukan khas: Boolean, Number dan String. Jenis data primitif tidak mempunyai sifat dan kaedah Apabila kami memanggil kaedah pada nilai jenis primitif untuk membacanya, proses akses akan berada dalam mod baca, dan objek jenis pembalut primitif yang sepadan akan dibuat di latar belakang, membolehkan kami untuk Panggil beberapa kaedah untuk memanipulasi data ini. Proses ini dibahagikan kepada tiga langkah: 1. Buat contoh jenis pembungkusan asal 2. Panggil kaedah yang ditentukan pada contoh 3. Musnahkan contoh.
Perbezaan utama antara jenis rujukan dan jenis pembalut primitif ialah kitaran hayat objek Objek jenis pembalut primitif yang dibuat secara automatik hanya wujud pada masa apabila baris kod dilaksanakan, dan kemudian dimusnahkan serta-merta, jadi kami tidak boleh. gantikan nilai jenis primitif pada masa jalankan.

Prakompilasi

Dalam buku "JavaScript You Don't Know", penulis menyatakan bahawa walaupun JavaScript diklasifikasikan sebagai "bahasa dinamik" atau " Bahasa pelaksanaan yang ditafsirkan", tetapi sebenarnya ia adalah bahasa yang disusun. Pelaksanaan JavaScript terbahagi kepada tiga langkah: 1. Analisis sintaks 2. Prakompilasi 3. Tafsiran dan pelaksanaan. Analisis sintaks dan pelaksanaan tafsiran tidak sukar untuk difahami Salah satunya adalah untuk memeriksa sama ada kod tersebut mempunyai ralat sintaks, dan satu lagi bertanggungjawab untuk melaksanakan program baris demi baris Walau bagaimanapun, peringkat prapenyusunan dalam JavaScript adalah lebih rumit.

Sebarang kod JavaScript mesti disusun sebelum pelaksanaan Dalam kebanyakan kes, proses kompilasi berlaku dalam beberapa mikrosaat sebelum kod dilaksanakan. Semasa fasa penyusunan, enjin JavaScript akan bermula daripada skop pelaksanaan kod semasa dan melakukan pertanyaan RHS pada kod untuk mendapatkan nilai pembolehubah. Kemudian semasa fasa pelaksanaan, enjin akan melaksanakan pertanyaan LHS dan memberikan nilai kepada pembolehubah.

Semasa fasa penyusunan, sebahagian daripada tugas enjin JavaScript ialah mencari semua pengisytiharan dan mengaitkannya dengan skop yang sesuai. Semasa proses prapengumpulan, jika ia berada dalam skop global, enjin JavaScript akan mula-mula mencipta objek global (objek GO, Objek Global) , dan mempromosikan pengisytiharan berubah-ubah dan pengisytiharan fungsi. Pembolehubah digalakkan mula-mula dimulakan kepada tidak ditentukan secara lalai, dan fungsi menggalakkan keseluruhan badan fungsi (Jika ia Untuk mentakrifkan fungsi dalam bentuk ungkapan fungsi, gunakan peraturan promosi pembolehubah) dan kemudian simpannya dalam pembolehubah global. Promosi pengisytiharan fungsi akan diutamakan daripada promosi perisytiharan pembolehubah Untuk perisytiharan pembolehubah, perisytiharan var berulang akan diabaikan oleh enjin, dan perisytiharan fungsi yang muncul kemudian boleh menimpa perisytiharan fungsi sebelumnya (. Sintaks pengisytiharan pembolehubah baharu ES6 berbeza sedikit, jadi kami tidak akan membincangkannya di sini buat masa ini) .

Bahagian dalam badan fungsi ialah skop bebas, dan fasa pra-kompilasi juga dilakukan di dalam badan fungsi. Di dalam badan fungsi, objek aktif (objek AO, Objek Aktif) akan dibuat terlebih dahulu, dan parameter dan pembolehubah formal akan diisytiharkan serta fungsi di dalam badan fungsi Pengisytiharan digalakkan, parameter formal dan pembolehubah dimulakan kepada tidak ditentukan, fungsi dalaman masih badan fungsi dalaman itu sendiri, dan kemudian ia disimpan dalam objek aktif.

Selepas fasa kompilasi selesai, kod JavaScript akan dilaksanakan. Proses pelaksanaan memberikan nilai kepada pembolehubah atau parameter formal dalam urutan. Enjin akan mencari pengisytiharan pembolehubah yang sepadan atau pengisytiharan parameter formal dalam skop, dan jika dijumpai, ia akan memberikan nilai kepada mereka. Untuk mod tidak ketat, jika pembolehubah ditetapkan tanpa pengisytiharan, enjin akan secara automatik dan secara tersirat membuat pengisytiharan untuk pembolehubah dalam persekitaran global Walau bagaimanapun, untuk mod ketat, ralat akan dilaporkan jika pembolehubah tidak diisytiharkan diberikan a nilai . Kerana pelaksanaan JavaScript adalah satu-benang, jika pembolehubah diperoleh sebelum operasi tugasan (pertanyaan LHS) dilaksanakan, (Pertanyaan RHS) dan output, anda akan mendapat hasil yang tidak ditentukan, kerana pembolehubah belum diberikan nilai pada masa ini.

Persekitaran dan skop pelaksanaan

 Setiap fungsi ialah objek Fungsi Contohnya, dalam JavaScript, setiap objek mempunyai sifat dalaman yang hanya boleh diakses oleh enjin JavaScript - [[Skop]]. Untuk fungsi, atribut [[Skop]] mengandungi koleksi objek dalam skop di mana fungsi itu dicipta - rantai skop. Apabila fungsi dicipta dalam persekitaran global, rantai skop fungsi memasukkan objek global yang mengandungi semua pembolehubah yang ditakrifkan dalam skop global.

Skop dalam boleh mengakses skop luar, tetapi skop luar tidak boleh mengakses dalam domain skop. Memandangkan JavaScript tidak mempunyai skop peringkat blok, pembolehubah yang ditakrifkan dalam pernyataan if atau pernyataan untuk gelung boleh diakses di luar pernyataan. Sebelum ES6, JavaScript hanya mempunyai skop global dan skop fungsi ES6 menambah mekanisme skop peringkat blok yang baharu.

Dan apabila fungsi itu dilaksanakan, persekitaran pelaksanaan yang dipanggil (konteks pelaksanaan, juga dipanggil konteks pelaksanaan) akan dibuat untuk fungsi pelaksanaan Objek dalaman . Setiap persekitaran pelaksanaan mempunyai rantai skopnya sendiri Apabila persekitaran pelaksanaan dibuat, bahagian atas rantai skopnya mula-mula dimulakan kepada objek dalam atribut [[Skop]] bagi fungsi yang sedang dijalankan. Sejurus selepas itu, objek aktif (termasuk semua pembolehubah tempatan, parameter bernama, set parameter argumen dan ini) apabila fungsi berjalan juga akan dibuat dan ditolak ke dalam fungsi Bahagian atas rantaian domain.

Persekitaran pelaksanaan yang sepadan dengan setiap pelaksanaan fungsi adalah unik, dan fungsi yang sama dipanggil berbilang kali Ini akan menghasilkan penciptaan pelbagai persekitaran pelaksanaan. Apabila fungsi menyelesaikan pelaksanaan, persekitaran pelaksanaan akan dimusnahkan. Apabila persekitaran pelaksanaan dimusnahkan, objek aktif juga dimusnahkan (persekitaran pelaksanaan global tidak akan dimusnahkan sehingga aplikasi keluar, seperti menutup halaman web atau penyemak imbas) .

Semasa pelaksanaan fungsi, setiap kali pembolehubah ditemui, ia akan melalui proses penghuraian pengecam untuk menentukan tempat untuk mendapatkan atau menyimpan data. Resolusi pengecam ialah proses mencari pengecam tahap demi tahap di sepanjang rantai skop Pembolehubah global sentiasa menjadi objek terakhir rantai skop (iaitu, objek tetingkap) <.>.

Dalam JavaScript, terdapat dua pernyataan yang boleh menukar rantai skop buat sementara waktu semasa pelaksanaan. Yang pertama ialah dengan pernyataan. Pernyataan dengan mencipta objek boleh ubah yang mengandungi semua sifat objek yang ditentukan oleh parameter, dan menolak objek ke kedudukan pertama rantai skop, yang bermaksud bahawa objek aktif fungsi itu diperah ke kedudukan kedua rantai skop. Walaupun ini menjadikan akses kepada sifat objek boleh ubah sangat pantas, mengakses pembolehubah tempatan, dsb. menjadi lebih perlahan. Pernyataan kedua yang boleh mengubah rantaian skop persekitaran pelaksanaan ialah klausa tangkapan dalam pernyataan cuba-tangkap. Apabila ralat berlaku dalam blok kod cuba, proses pelaksanaan akan secara automatik melompat ke klausa tangkapan, dan kemudian objek pengecualian akan ditolak ke dalam objek berubah dan diletakkan di bahagian atas skop. Di dalam blok tangkapan, semua pembolehubah tempatan fungsi akan diletakkan dalam objek rantai skop kedua. Setelah klausa tangkapan dilaksanakan, rantai skop kembali ke keadaan sebelumnya.

Pembina

Pembina dalam JavaScript boleh digunakan untuk mencipta objek jenis tertentu. Untuk membezakannya daripada fungsi lain, pembina biasanya bermula dengan huruf besar. Walau bagaimanapun, ini tidak perlu dalam JavaScript, kerana JavaScript tidak mempunyai sintaks khas untuk menentukan pembina. Dalam JavaScript, satu-satunya perbezaan antara pembina dan fungsi lain ialah cara ia dipanggil. Sebarang fungsi, selagi ia dipanggil melalui operator baharu, boleh digunakan sebagai pembina.

JavaScriptFungsi mempunyai empat mod panggilan: 1. Mod panggilan fungsi bebas, seperti foo (arg). 2. Mod panggilan kaedah, seperti obj.foo(arg). 3. Mod panggilan pembina, seperti foo(arg) baharu. 4.panggil/guna mod panggilan, seperti foo.call(this,arg1,arg2) atau foo.apply(this,args) (args di sini ialah tatasusunan).

Untuk mencipta contoh pembina dan memainkan peranan sebagai pembina, anda mesti menggunakan operator baharu. Apabila kita menggunakan operator baharu untuk membuat instantiate pembina, langkah berikut akan dilakukan di dalam pembina:

1. Secara tersirat mencipta objek ini kosong
2. Jalankan kod dalam pembina (tambah atribut pada arus ini objek )
3. Secara tersirat mengembalikan objek ini semasa

Jika pembina secara eksplisit mengembalikan objek, maka contoh itu dikembalikan Objek, jika tidak, ia adalah objek ini dikembalikan secara tersirat.

Apabila kita memanggil pembina untuk mencipta contoh, contoh itu akan mempunyai semua atribut contoh dan kaedah pembina. Untuk contoh berbeza yang dibuat melalui pembina, sifat dan kaedah contoh mereka adalah bebas. Walaupun ia adalah nilai jenis rujukan dengan nama yang sama, kejadian yang berbeza tidak akan menjejaskan satu sama lain.

Prototaip dan rantaian prototaip

Salah satu intipati juga merupakan salah satu kesukaran bahasa ini. Prototaip prototaip (prototaip eksplisit) ialah atribut unik fungsi Setiap kali fungsi dicipta, fungsi itu secara automatik akan mencipta atribut prototaip dan menunjuk ke objek prototaip fungsi tersebut. Semua objek prototaip secara automatik akan memperoleh pembina (pembina, yang juga boleh diterjemahkan sebagai pembina) atribut Atribut ini mengandungi penunjuk kepada fungsi di mana prototaip atribut terletak (iaitu, pembina itu sendiri) penunjuk ke . Apabila kita mencipta contoh melalui pembina, contoh itu akan mengandungi sifat dalaman [[Prototaip]] (prototaip tersirat), yang juga menunjuk kepada objek prototaip pembina. Dalam Firefox, Safari dan Chrome, setiap objek boleh mengakses sifat [[Prototaip]] mereka melalui atribut __proto__. Untuk penyemak imbas lain, atribut ini tidak dapat dilihat sepenuhnya oleh skrip.

Atribut prototaip pembina dan [[Prototaip]] contoh kedua-duanya menunjuk ke objek prototaip pembina, dan sifat [[ contoh Tiada hubungan langsung antara Prototaip]] dan pembina. Untuk mengetahui sama ada sifat [[Prototaip]] sesuatu contoh menunjuk kepada objek prototaip pembina tertentu, kita boleh menggunakan kaedah isPrototypeOf() atau Object.getPrototypeOf().

Setiap kali sifat bagi contoh objek dibaca, carian dilakukan, menyasarkan sifat dengan nama yang diberikan. Carian pertama bermula dari contoh objek itu sendiri Jika atribut dengan nama yang diberikan ditemui dalam contoh, nilai atribut dikembalikan jika tidak dijumpai, carian diteruskan untuk objek prototaip yang ditunjukkan oleh [[Prototaip]; ] atribut objek. Dalam prototaip Mencari objek untuk harta dengan nama yang diberikan, dan mengembalikan nilai harta itu jika ditemui.

Untuk menentukan pembina mana objek itu merupakan contoh langsung, anda boleh mengakses pembina secara langsung pada Properties contoh, contoh akan membaca sifat pembina pada objek prototaip melalui [[Prototaip]] dan mengembalikan pembina itu sendiri. Nilai dalam objek prototaip boleh diakses melalui contoh objek, tetapi ia tidak boleh diubah suai melalui contoh objek. Jika kami menambah sifat dalam contoh dengan nama yang sama dengan objek prototaip contoh, maka kami mencipta sifat dalam contoh ini akan menghalang kami daripada mengakses harta itu dalam objek prototaip, tetapi ia tidak akan mengubah suai sifat itu. Hanya menetapkan sifat contoh kepada null tidak memulihkan akses kepada harta dalam objek prototaip Untuk memulihkan akses kepada harta dalam objek prototaip, anda boleh menggunakan operator padam untuk memadam sepenuhnya harta daripada contoh objek.

Gunakan kaedah hasOwnProperty() untuk mengesan sama ada sesuatu sifat wujud dalam contoh atau dalam prototaip. Kaedah ini akan kembali benar hanya jika sifat yang diberikan wujud dalam contoh objek. Untuk mendapatkan semua sifat contoh terhitung objek itu sendiri, anda boleh menggunakan kaedah ES5 Object.keys(). Untuk mendapatkan semua sifat contoh, sama ada boleh dikira atau tidak, anda boleh menggunakan kaedah Object.getOwnPropertyNames().

Prototaip adalah dinamik, dan sebarang pengubahsuaian yang dibuat pada objek prototaip boleh dipantulkan serta-merta daripada contoh, tetapi jika ia diulang Menulis keseluruhan objek prototaip, keadaannya berbeza. Memanggil pembina akan menambah penuding [[Prototaip]] kepada objek prototaip asal kepada contoh objek Selepas menulis semula keseluruhan objek prototaip, pembina menunjuk ke objek prototaip baharu Semua sifat dan kaedah objek prototaip wujud dengan prototaip baharu. pada objek; dan contoh objek juga menunjuk kepada objek prototaip asal, jadi sambungan antara pembina dan objek prototaip asal yang menunjuk kepada objek prototaip yang sama terputus, kerana mereka menunjukkan objek prototaip yang berbeza masing-masing.

Untuk memulihkan sambungan ini, anda boleh membuat instantiate contoh objek selepas menulis semula prototaip pembina, atau mengubah suai contoh objek Atribut __proto__ menunjuk semula objek prototaip baharu pembina.

JavaScript menggunakan rantaian prototaip sebagai cara utama untuk melaksanakan warisan. Ia menggunakan prototaip untuk membenarkan satu jenis rujukan mewarisi sifat dan kaedah jenis rujukan yang lain. Contoh pembina mempunyai atribut [[Prototaip]] yang menunjuk ke objek prototaip Apabila kita membuat objek prototaip pembina sama dengan contoh jenis lain, objek prototaip juga akan mengandungi penunjuk penunjuk [[Prototaip]]. kepada prototaip yang lain Jika prototaip lain adalah contoh jenis lain... dan seterusnya, rantaian kejadian dan prototaip terbentuk. Ini adalah konsep asas rantai prototaip yang dipanggil.

Rantaian prototaip memanjangkan mekanisme carian prototaip Apabila atribut contoh dibaca, atribut itu mula-mula dicari dalam contoh. Jika atribut tidak ditemui, carian untuk objek prototaip yang ditunjukkan oleh contoh [[Prototaip]] akan diteruskan . Objek prototaip [[Prototaip]] menghala ke objek prototaip yang lain... Proses carian terus mencari ke atas di sepanjang rantaian prototaip Jika atribut atau kaedah yang ditentukan tidak dapat ditemui, proses carian akan dilaksanakan satu demi satu rantai prototaip Ia akan berhenti pada penghujungnya.

Jika objek prototaip fungsi tidak diubah suai, semua jenis rujukan mempunyai atribut [[Prototaip]] yang menunjuk ke objek prototaip Object secara lalai. Oleh itu, prototaip lalai semua fungsi ialah contoh Object, yang merupakan sebab asas mengapa semua jenis tersuai mewarisi kaedah lalai seperti toString() dan valueOf(). Anda boleh menggunakan pengendali instanceof atau kaedah isPrototypeOf() untuk menentukan sama ada prototaip pembina wujud dalam rantai prototaip contoh itu.

Walaupun rantai prototaip sangat berkuasa, ia juga mempunyai beberapa masalah. Masalah pertama ialah nilai jenis rujukan pada objek prototaip dikongsi oleh semua kejadian, yang bermaksud bahawa sifat jenis rujukan atau kaedah kejadian yang berbeza menghala ke memori timbunan yang sama Mengubah suai nilai rujukan pada prototaip satu contoh akan mempengaruhi semua contoh lain pada masa yang sama Nilai rujukan contoh pada objek prototaip, itulah sebabnya sifat atau kaedah persendirian ditakrifkan dalam pembina dan bukannya pada prototaip. Masalah kedua dengan rantai prototaip ialah apabila kita menyamakan prototaip prototaip pembina dengan contoh pembina lain, jika kita menghantar parameter kepada pembina lain untuk menetapkan nilai atribut pada masa ini, maka semua sifat berdasarkan asal constructor will Atribut contoh ini akan diberikan nilai yang sama kerana rantaian prototaip, dan ini kadangkala bukan hasil yang kita inginkan.

Penutupan

Penutupan ialah salah satu ciri JavaScript yang paling berkuasa, dalam JavaScript , penutupan, merujuk kepada fungsi yang mempunyai hak untuk mengakses pembolehubah dalam skop fungsi lain, yang bermaksud bahawa fungsi itu boleh mengakses data di luar skop tempatan. Cara biasa untuk membuat penutupan ialah mencipta fungsi di dalam fungsi lain dan mengembalikan fungsi ini.

Secara umumnya, apabila fungsi itu dilaksanakan, objek aktif tempatan akan dimusnahkan, dan hanya skop global akan disimpan dalam ingatan itu. Bagaimanapun, keadaan berbeza dengan penutupan.

Atribut [[Skop]] bagi fungsi penutupan akan dimulakan kepada rantai skop fungsi yang membungkusnya, jadi penutupan mengandungi rujukan kepada objek dalam rantai skop yang sama dengan persekitaran pelaksanaan. Secara umumnya, objek aktif fungsi akan dimusnahkan bersama-sama dengan persekitaran pelaksanaan. Tetapi apabila penutupan diperkenalkan, objek aktif fungsi asal tidak boleh dimusnahkan kerana rujukan masih wujud dalam atribut [[Skop]] penutupan. Ini bermakna fungsi penutupan memerlukan lebih banyak overhed memori daripada fungsi bukan penutup, yang membawa kepada lebih banyak kebocoran memori. Di samping itu, apabila penutupan mengakses objek aktif fungsi pembalut asal, ia perlu terlebih dahulu menyelesaikan pengecam objek aktifnya sendiri dalam rantai skop dan mencari lapisan atas Oleh itu, penutupan menggunakan pembolehubah fungsi pembalut asal juga memudaratkan prestasi mempunyai kesan yang besar.

Setiap kali anda menggunakan fungsi panggil balik dalam pemasa, pendengar acara, permintaan Ajax, komunikasi merentas tetingkap, Pekerja Web atau sebarang tugas tak segerak atau segerak yang lain, anda sebenarnya menggunakan penutupan.

Masalah penutupan biasa ialah menggunakan pemasa dalam gelung untuk kepada pembolehubah gelung output:

Kod ini, untuk mereka yang tidak biasa dengan JavaScript penutupan Sebagai contoh, anda boleh mengambil mudah bahawa keputusan akan mengeluarkan 0, 1, 2, dan 3 dalam urutan Walau bagaimanapun, keadaan sebenar ialah empat nombor yang dikeluarkan oleh kod ini semuanya 4.

Ini kerana, oleh kerana pemasa ialah mekanisme pemuatan tak segerak, ia tidak akan dilaksanakan sehingga gelung for dilalui. Setiap kali pemasa dilaksanakan, pemasa mencari pembolehubah i dalam skop luarnya. Memandangkan gelung telah tamat, pembolehubah i dalam skop luaran telah dikemas kini kepada 4, jadi pembolehubah i yang diperolehi oleh empat pemasa semuanya adalah 4, bukannya keluaran ideal kami 0, 1, 2, 3.

Untuk menyelesaikan masalah ini, kita boleh mencipta skop baharu yang membungkus fungsi pelaksanaan segera, dan menyimpan pembolehubah i skop luaran dalam setiap gelung ke skop yang baru dibuat, supaya pemasa boleh melaksanakan fungsi setiap kali Pertama dapatkan nilai daripada skop baharu Kita boleh menggunakan fungsi pelaksanaan segera untuk mencipta skop baharu ini:

Dengan cara ini, hasil pelaksanaan gelung akan dikeluarkan. 0, 1, dalam urutan 2 dan 3, kita juga boleh memudahkan fungsi pelaksanaan segera ini dan teruskan parameter sebenar i kepada fungsi pelaksanaan segera, jadi tidak perlu menetapkan nilai kepada j di dalam:

Sudah tentu, tidak perlu menggunakan fungsi pelaksanaan segera Anda juga boleh mencipta fungsi bukan tanpa nama dan melaksanakannya setiap kali ia bergelung, tetapi ini akan mengambil lebih banyak memori untuk disimpan. pengisytiharan fungsi.

Oleh kerana tiada tetapan skop peringkat blok sebelum ES6, kami hanya boleh menyelesaikan masalah ini dengan mencipta skop baharu secara manual. ES6 mula menyediakan skop peringkat blok Kita boleh menggunakan let untuk menentukan skop peringkat blok:

Operator let akan mencipta skop peringkat blok dan mengisytiharkannya melalui. biarkan Pembolehubah disimpan dalam skop blok semasa, jadi setiap fungsi yang dilaksanakan serta-merta akan mencari pembolehubah dari skop blok semasa setiap kali.

Terdapat juga takrifan khas let, yang menyebabkan pembolehubah diisytiharkan lebih daripada sekali semasa gelung Ia akan diisytiharkan semula setiap kali gelung digelung dan pembolehubah yang baru diisytiharkan akan dimulakan dengan nilai pada penghujung gelung sebelumnya, jadi, Kita juga boleh menggunakan let terus di kepala gelung for:

ini menunjuk ke

Kata kunci ini ialah salah satu mekanisme paling kompleks dalam JavaScript Ia ditakrifkan secara automatik dalam skop semua fungsi. Ia adalah mudah untuk orang memahami ini sebagai menunjuk kepada fungsi itu sendiri Walau bagaimanapun, dalam ES5, ini tidak terikat apabila fungsi itu diisytiharkan apabila fungsi itu dijalankan. Ia tidak ada kena mengena dengan di mana fungsi diisytiharkan. (Ini dalam fungsi anak panah baharu dalam ES6 adalah berbeza, dan penunjuknya bergantung pada kedudukan pengisytiharan fungsi.)

Ingat apa yang saya nyatakan sebelum ini Adakah terdapat empat mod panggilan fungsi: 1.Mod panggilan fungsi bebas, seperti foo(arg). 2.Mod panggilan kaedah objek, seperti obj.foo(arg). 3.Mod panggilan pembina, seperti foo(arg) baharu. 4.call/applyMod panggilan, seperti foo.call(this) atau foo.apply(this).

Untuk mod panggilan fungsi bebas, dalam mod tidak ketat, bahagian dalam mod ini akan menghala ke objek global secara lalai. Dalam mod ketat, ini tidak dibenarkan untuk terikat pada objek global secara lalai, jadi ia akan terikat kepada tidak ditentukan.

Untuk mod panggilan kaedah objek, ini dalam fungsi akan menunjuk ke objek itu sendiri yang memanggilnya:

Untuk mod panggilan pembina, langkah pelaksanaan di dalam pembina telah diperkenalkan sebelum ini:
1. Secara tersirat cipta objek kosong ini
2. Jalankan kod dalam pembina (tambah atribut pada objek ini semasa)
3. Secara tersirat mengembalikan objek ini semasa

Oleh itu, apabila memanggil fungsi menggunakan kaedah baharu, ini akan menunjukkan objek ini secara tersirat dan bebas di dalam pembina Semua sifat atau kaedah yang ditambahkan melalui ini akhirnya akan akan ditambahkan pada objek kosong ini dan dikembalikan kepada contoh pembina.

Untuk panggilan/guna mod panggilan, ini dalam fungsi akan terikat pada parameter pertama yang anda masukkan, seperti yang ditunjukkan dalam rajah:

foo.apply() dan foo.call() mempunyai fungsi yang sama untuk menukar titik ini Satu-satunya perbezaan ialah parameter kedua diluluskan dalam format Parameter.

Mengenai prinsip asas JavaScript, saya akan menulisnya buat sementara waktu di sini hari ini saya akan terus mengemas kini kandungan tentang JavaScript pada masa hadapan.

[Cadangan berkaitan: tutorial pembelajaran javascript]

Atas ialah kandungan terperinci Pemahaman mendalam tentang mekanisme asas JS seperti jenis data JS, prapenyusun dan konteks pelaksanaan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:csdn.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam