Saya mencoba memahami di balik layar tirai Javascript dan agak terjebak dalam memahami penciptaan objek bawaan, khususnya Obyek dan Fungsi dan hubungan di antara mereka.
Ketika saya membaca bahwa semua objek bawaan seperti Array, String dll adalah ekstensi (diwarisi) dari Object, saya berasumsi bahwa Object adalah objek built-in pertama yang dibuat dan sisa objek yang diwarisi darinya. Tapi itu tidak masuk akal ketika Anda mengetahui bahwa Objek hanya dapat dibuat oleh fungsi tetapi kemudian fungsi juga tidak lain adalah objek Fungsi. Semacam itu mulai terdengar seperti dilema ayam dan ayam.
Hal lain yang sangat membingungkan adalah, jika saya console.log(Function.prototype)
mencetak fungsi tetapi ketika saya mencetaknya console.log(Object.prototype)
mencetak objek. Mengapa Function.prototype
suatu fungsi saat itu dimaksudkan untuk menjadi objek?
Juga, menurut dokumentasi Mozilla setiap javascript function
adalah ekstensi Function
objek tetapi ketika Anda console.log(Function.prototype.constructor)
kembali berfungsi. Sekarang bagaimana Anda dapat menggunakan sesuatu untuk membuatnya sendiri (Mind = blown).
Hal terakhir, Function.prototype
adalah fungsi tetapi saya dapat mengakses constructor
fungsi menggunakan Function.prototype.constructor
apakah itu artinya Function.prototype
adalah fungsi yang mengembalikan prototype
objek
sumber
Function.prototype
bisa menjadi fungsi dan memiliki bidang dalam. Jadi tidak, Anda tidak menjalankan fungsi prototipe ketika melalui struktur itu. Akhirnya ingat bahwa ada mesin yang menafsirkan Javascript, jadi Obyek dan Fungsi mungkin dibuat di dalam mesin dan bukan dari Javascript dan referensi khusus sepertiFunction.prototype
danObject.prototype
mungkin hanya ditafsirkan dengan cara khusus oleh mesin.Jawaban:
Ini rumit, mudah disalahpahami, dan banyak buku Javascript pemula yang salah, jadi jangan percaya semua yang Anda baca.
Saya adalah salah satu pelaksana mesin JS Microsoft pada 1990-an dan pada komite standardisasi, dan saya membuat sejumlah kesalahan dalam menyusun jawaban ini. (Meskipun karena saya belum mengerjakan ini selama lebih dari 15 tahun saya mungkin bisa dimaafkan.) Itu adalah hal yang rumit. Tapi begitu Anda memahami warisan prototipe, semuanya masuk akal.
Mulailah dengan membuang semua yang Anda ketahui tentang warisan berbasis kelas. JS menggunakan pewarisan berbasis prototipe.
Selanjutnya, pastikan Anda memiliki definisi yang sangat jelas di kepala Anda tentang apa arti "warisan". Orang yang terbiasa dengan bahasa OO seperti C # atau Java atau C ++ berpikir bahwa pewarisan berarti subtipe, tetapi pewarisan tidak berarti subtipe. Warisan berarti bahwa anggota dari satu hal juga anggota dari hal lain . Itu tidak selalu berarti bahwa ada hubungan subtyping antara hal-hal itu! Begitu banyak kesalahpahaman dalam teori jenis adalah hasil dari orang tidak menyadari bahwa ada perbedaan.
Ini benar-benar salah. Beberapa objek tidak dibuat dengan memanggil
new F
beberapa fungsiF
. Beberapa objek dibuat oleh runtime JS dari ketiadaan sama sekali. Ada telur yang tidak diletakkan oleh ayam apa pun . Mereka baru saja dibuat oleh runtime saat dijalankan.Katakanlah apa aturannya dan mungkin itu akan membantu.
null
.prototype
anggota dari suatu objek biasanya tidak prototipe dari objek.prototype
anggota objek fungsi F adalah objek yang akan menjadi prototipe objek yang dibuat olehnew F()
.__proto__
anggota yang benar-benar memberikan prototipe mereka. (Ini sekarang sudah usang. Jangan mengandalkan itu.)prototype
saat dibuat.Function.prototype
.Mari kita simpulkan.
Object
adalahFunction.prototype
Object.prototype
adalah objek prototipe objek.Object.prototype
adalahnull
Function
isFunction.prototype
- ini adalah salah satu situasi langka di manaFunction.prototype
sebenarnya adalah prototipeFunction
!Function.prototype
adalah objek prototipe fungsi.Function.prototype
adalahObject.prototype
Misalkan kita membuat fungsi Foo.
Foo
adalahFunction.prototype
.Foo.prototype
adalah objek prototipe Foo.Foo.prototype
adalahObject.prototype
.Anggap saja kita katakan
new Foo()
Foo.prototype
Pastikan itu masuk akal. Mari kita menggambarnya. Oval adalah instance objek. Tepi bisa
__proto__
berarti "prototipe", atauprototype
berarti "prototype
properti".Yang harus dilakukan runtime adalah membuat semua objek itu dan menetapkan berbagai propertinya sesuai. Saya yakin Anda bisa melihat bagaimana itu akan dilakukan.
Sekarang mari kita lihat contoh yang menguji pengetahuan Anda.
Apa yang dicetak ini?
Nah, apa
instanceof
artinya?honda instanceof Car
berarti "Car.prototype
sama dengan benda apa punhonda
di rantai prototipe?"Ya itu.
honda
Prototipenya sudahCar.prototype
, jadi kita selesai. Ini mencetak benar.Bagaimana dengan yang kedua?
honda.constructor
tidak ada jadi kami berkonsultasi dengan prototipe, yaituCar.prototype
. KetikaCar.prototype
objek itu dibuat secara otomatis diberi properticonstructor
sama denganCar
, jadi ini benar.Sekarang bagaimana dengan ini?
Apa yang dicetak oleh program ini?
Sekali lagi,
lizard instanceof Reptile
berarti "Reptile.prototype
sama dengan objek apa pun dilizard
di rantai prototipe?"Ya itu.
lizard
prototipe adalahReptile.prototype
, jadi kita selesai. Ini mencetak benar.Sekarang bagaimana
Anda mungkin berpikir bahwa ini juga mencetak benar, karena
lizard
dibangun dengannew Reptile
tetapi Anda akan salah. Alasan itu keluar.lizard
punyaconstructor
properti? Tidak. Oleh karena itu kami melihat prototipe.lizard
adalahReptile.prototype
, yaituAnimal
.Animal
punyaconstructor
properti? Tidak. Jadi kita melihat prototipe itu.Animal
adalahObject.prototype
, danObject.prototype.constructor
dibuat oleh runtime dan sama denganObject
.Kita seharusnya mengatakan
Reptile.prototype.constructor = Reptile;
pada suatu titik di sana, tetapi kita tidak ingat untuk melakukannya!Pastikan semua masuk akal bagi Anda. Gambarlah beberapa kotak dan panah jika masih membingungkan.
Prototipe fungsi didefinisikan sebagai fungsi yang, ketika dipanggil, kembali
undefined
. Kita sudah tahu bahwaFunction.prototype
adalahFunction
prototipe, anehnya. Jadi karenaFunction.prototype()
itu legal, dan ketika Anda melakukannya, Andaundefined
kembali. Jadi itu sebuah fungsi.The
Object
prototipe tidak memiliki properti ini; itu tidak bisa dipanggil. Itu hanya sebuah objek.Function.prototype.constructor
hanyaFunction
, jelas. DanFunction
merupakan fungsi.Anda terlalu memikirkan ini . Semua yang diperlukan adalah bahwa runtime membuat banyak objek saat dijalankan. Objek hanyalah tabel pencarian yang mengaitkan string dengan objek. Ketika runtime dijalankan, itu harus lakukan adalah membuat beberapa objek lusin kosong, dan kemudian mulai menempatkan
prototype
,__proto__
,constructor
, dan sebagainya properti dari setiap objek sampai mereka membuat grafik yang mereka butuhkan untuk membuat.Akan sangat membantu jika Anda mengambil diagram yang saya berikan di atas dan menambahkan
constructor
pinggirannya. Anda akan segera melihat bahwa ini adalah grafik objek yang sangat sederhana dan runtime tidak akan bermasalah saat membuatnya.Latihan yang baik adalah melakukannya sendiri. Di sini, saya akan memulai Anda. Kami akan menggunakan
my__proto__
berarti "objek prototipe" danmyprototype
berarti "properti prototipe".Dan seterusnya. Bisakah Anda mengisi sisa program untuk membangun satu set objek yang memiliki topologi yang sama dengan objek bawaan Javascript "asli"? Jika Anda melakukannya, Anda akan menemukannya sangat mudah.
Objek dalam JavaScript hanyalah tabel pencarian yang mengaitkan string dengan objek lain . Itu dia! Tidak ada keajaiban di sini. Anda mendapatkan diri Anda terikat di simpul karena Anda membayangkan kendala yang sebenarnya tidak ada, seperti setiap objek harus dibuat oleh konstruktor.
Fungsi hanyalah objek yang memiliki kemampuan tambahan: untuk dipanggil. Jadi, ikuti program simulasi kecil Anda dan tambahkan
.mycallable
properti ke setiap objek yang menunjukkan apakah itu dapat dipanggil atau tidak. Sesederhana itu.sumber
__proto__
. The__proto__
prototipe objek adalah null. The__proto__
darinew X()
adalahX.prototype
. Semua objek fungsi memiliki prototipe fungsi untuk__proto__
kecuali untuk prototipe fungsi itu sendiri.Object
danFunction
prototipe fungsi adalah fungsi. Aturan-aturan itu semuanya mudah, dan mereka menentukan topologi grafik objek awal.Anda sudah memiliki banyak jawaban bagus, tetapi saya hanya ingin memberikan jawaban singkat dan jelas untuk jawaban Anda tentang bagaimana semua ini bekerja, dan jawaban itu adalah:
SIHIR!!!
Sungguh, itu dia.
Orang-orang yang melaksanakan ECMAScript mesin eksekusi harus menerapkan aturan ECMAScript, tetapi tidak mematuhi oleh mereka dalam pelaksanaannya.
Spesifikasi Naskah ECMAS mengatakan bahwa A mewarisi dari B tetapi B adalah turunan dari A? Tidak masalah! Buat A pertama dengan pointer prototipe
NULL
, buat B sebagai instance dari A, lalu perbaiki pointer prototipe A untuk menunjuk ke B sesudahnya. Peasy mudah.Anda bilang, tapi tunggu, tidak ada cara untuk mengubah pointer prototipe di ECMAScript! Tapi, ini masalahnya: kode ini tidak berjalan di mesin ECMAScript, kode ini adalah mesin ECMAScript. Itu memang memiliki akses ke objek internal yang kode ECMAScript berjalan pada mesin tidak memiliki. Singkatnya: ia dapat melakukan apa pun yang diinginkannya.
Omong-omong, jika Anda benar-benar ingin, Anda hanya perlu melakukan ini satu kali: setelah itu, Anda dapat, misalnya, membuang memori internal Anda dan memuat dump ini setiap kali Anda memulai mesin ECMAScript Anda.
Perhatikan bahwa semua ini masih berlaku, bahkan jika mesin ECMAScript sendiri ditulis dalam ECMAScript (seperti halnya Mozilla Narcissus, misalnya). Bahkan kemudian, kode ECMAScript yang mengimplementasikan mesin masih memiliki akses penuh ke mesin yang sedang diimplementasikan , meskipun tentu saja tidak memiliki akses ke mesin yang sedang berjalan .
sumber
Dari ECMA spec 1
Saya tidak melihat bagaimana ini bisa menjadi lebih jelas !!!
</sarcasm>
Lebih jauh ke bawah kita melihat:
Jadi kita dapat melihat bahwa prototipe adalah objek, tetapi tidak harus merupakan objek fungsi.
Juga, kami memiliki titbit yang menarik ini
http://www.ecma-international.org/ecma-262/8.0/index.html#sec-object-objects
dan
sumber
sarcasm
Sebaliknya, moniker Anda , teks ini benar-benar buram bagi pemula.Jenis-jenis berikut mencakup setiap nilai dalam JavaScript:
boolean
number
undefined
(yang termasuk nilai tunggalundefined
)string
symbol
("hal-hal" unik abstrak yang dibandingkan dengan referensi)object
Setiap objek (yaitu semuanya) dalam JavaScript memiliki prototipe, yang merupakan jenis objek.
Prototipe berisi fungsi, yang juga merupakan semacam objek 1 .
Objek juga memiliki konstruktor, yang merupakan fungsi, dan karena itu semacam objek.
Semuanya rekursif, tetapi implementasinya dapat melakukannya secara otomatis karena, tidak seperti kode JavaScript, ia dapat membuat objek tanpa harus memanggil fungsi JavaScript (karena objek hanyalah memori yang dikendalikan oleh implementasi).
Sebagian besar sistem objek dalam banyak bahasa yang diketik secara dinamis berbentuk lingkaran 2 seperti ini. Sebagai contoh, dalam Python, kelas adalah objek, dan kelas kelas adalah
type
,type
karena itu merupakan turunan dari dirinya sendiri.Ide terbaik adalah dengan hanya menggunakan alat yang disediakan bahasa, dan tidak terlalu memikirkan bagaimana mereka sampai di sana.
1 Fungsi agak istimewa karena mereka dapat dipanggil, dan mereka adalah satu-satunya nilai yang dapat berisi data buram (tubuh mereka dan mungkin penutup).
2 Ini sebenarnya lebih merupakan pita yang tersiksa dan bercabang yang tertekuk ke belakang dengan sendirinya, tetapi "bundar" cukup dekat.
sumber