Kapan harus menggunakan pemrograman prototipikal dalam JavaScript

15

Saya telah menghabiskan sedikit waktu mengembangkan widget sederhana untuk proyek dengan cara berikut:

var project = project || {};

(function() {

  project.elements = {
    prop1: val1,
    prop2: val2
  }

  project.method1 = function(val) {
    // Do this
  }

  project.method2 = function(val) {
    // Do that
  }

  project.init = function() {
    project.method1(project.elements.prop1)
    project.method2(project.elements.prop2)
  }
})()

project.init();

Tapi saya sudah mulai mengubah format saya sebagai berikut:

function Project() {
  this.elements = {
    prop1: val1,
    prop2: val2
  }

  this.method_one(this.elements.prop1);
  this.method_two(this.elements.prop2);
}

Project.prototype.method_one = function (val) {
  // 
};

Project.prototype.method_two = function (val) {
  //
};

new Project();

Memang, ini adalah contoh konyol jadi jangan sampai terlilit di axel. Tetapi apa perbedaan fungsional dan kapan saya harus memilih yang satu atau yang lain?

JDillon522
sumber
Saya pikir contoh kode pertama Anda tidak akan berfungsi karena proyek tidak meninggalkan ruang lingkup. Untuk menggunakan warisan di JS Anda menggunakan prototyping. Contoh pertama tidak dimaksudkan untuk memperpanjang proyek, sehingga usabilitas ulang mungkin terbatas.
Aitch
Ya saya tidak sengaja menempatkan projectdeklarasi di dalam fungsi. Diperbarui.
JDillon522
sama disini. Contoh pertama adalah statis, kedua berorientasi objek.
Aitch
1
Jika Anda hanya menggunakan satu instance objek, maka tidak ada alasan apa pun untuk menggunakan definisi prototipal. Dan apa yang tampaknya Anda perlukan - adalah format modul - ada banyak opsi untuk itu, lihat: addyosmani.com/writing-modular-js
c69
1
Yang pertama untuk pola singleton Yang kedua untuk non-singleton (ketika 1 kelas dapat memiliki banyak objek)
Kokizzu

Jawaban:

6

Perbedaan pertama dapat diringkas sebagai: thismerujuk pada Instance dari kelas. prototypemengacu pada Definisi .

Katakanlah kita memiliki kelas berikut:

var Flight = function ( number ) { this.number = number; };

Jadi di sini kita melekat this.numberpada setiap instance kelas, dan itu masuk akal karena setiap orang Flightharus memiliki nomor penerbangan mereka sendiri.

var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );

Sebaliknya, prototypemendefinisikan satu properti yang dapat diakses oleh semua instance.

Sekarang jika kita ingin mendapatkan nomor penerbangan, kita cukup menulis cuplikan berikut ini dan semua instance kita akan mendapatkan Referensi ke objek yang baru di-prototipe ini.

Flight.prototype.getNumber = function () { return this.number; };

Perbedaan kedua adalah tentang cara JavaScript mencari properti suatu objek. Saat Anda mencari Object.whatever, JavaScript bergerak sampai ke objek Obyek utama (objek yang diwarisi dari yang lainnya), dan segera setelah menemukan kecocokan, ia akan kembali atau memanggilnya.

Tapi itu hanya terjadi untuk properti prototipe. Jadi, jika Anda memiliki suatu tempat di tingkat yang lebih tinggi this.whatever, JavaScript tidak akan menganggapnya sebagai pertandingan dan akan melanjutkan pencarian.

Mari kita lihat bagaimana itu terjadi dalam kenyataan.

Catatan pertama bahwa [hampir] semuanya adalah Objek dalam JavaScript. Coba ini:

typeof null

Sekarang mari kita lihat apa yang ada di dalam Object(perhatikan Huruf Besar Odan .pada akhirnya). Di Alat Pengembang Google Chrome saat Anda memasukkan, .Anda akan mendapatkan daftar properti yang tersedia di dalam objek tertentu.

Object.

Sekarang lakukan hal yang sama untuk Function:

Function.

Anda mungkin memperhatikan namemetodenya. Pergi saja dan nyalakan dan mari kita lihat apa yang terjadi:

Object.name
Function.name

Sekarang mari kita buat fungsi:

var myFunc = function () {};

Dan mari kita lihat apakah kita punya namemetode di sini juga:

myFunc.name

Anda harus mendapatkan string kosong, tapi tidak apa-apa. Anda seharusnya tidak mendapatkan Kesalahan atau Pengecualian.

Sekarang mari kita tambahkan sesuatu seperti dewa itu Objectdan lihat apakah kita mendapatkannya di tempat lain juga?

Object.prototype.test = "Okay!";

Dan itu dia:

Object.prototype.test
Function.prototype.test
myFunc.prototype.test

Dalam semua kasus, Anda harus melihat "Okay!".

Mengenai pro dan kontra dari masing-masing metode Anda dapat mempertimbangkan prototyping sebagai cara "lebih efisien" dalam melakukan sesuatu, karena itu membuat referensi pada setiap contoh daripada menyalin seluruh properti di setiap objek. Di sisi lain itu adalah contoh Tightly Coupling yang merupakan no-no besar sampai Anda benar-benar dapat membenarkan alasannya. thiscukup rumit karena relevan dengan konteks. Anda dapat menemukan banyak sumber daya yang baik secara gratis di internet.

Itu semua mengatakan, kedua cara hanyalah alat bahasa dan itu benar-benar tergantung pada Anda dan masalah yang Anda coba pecahkan untuk memilih yang lebih cocok.

Jika Anda perlu memiliki properti agar relevan dengan setiap instance kelas, maka gunakan this. Jika Anda perlu memiliki properti agar berfungsi sama di setiap instance, kemudian gunakan prototype.

Memperbarui

Mengenai cuplikan sampel Anda, yang pertama adalah contoh Singleton , jadi masuk akal untuk digunakan thisdalam tubuh objek. Anda juga dapat meningkatkan contoh Anda dengan menjadikannya modular seperti ini (dan Anda tidak perlu selalu menggunakannya thisjuga).

/* Assuming it will run in a web browser */
(function (window) {
    window.myApp = {
        ...
    }
})( window );

/* And in other pages ... */
(function (myApp) {
    myApp.Module = {
        ...
    }
})( myApp );

/* And if you prefer Encapsulation */
(function (myApp) {
    myApp.Module = {
         "foo": "Foo",
         "bar": function ( string ) {
             return string;
         },
         return {
             "foor": foo,
             "bar": bar
         }
    }
})( myApp );

Cuplikan kedua Anda tidak masuk akal karena pertama kali Anda gunakan thisdan kemudian Anda mencoba meretasnya prototype, yang tidak berfungsi karena thisdiprioritaskan prototype. Saya tidak yakin apa yang Anda harapkan dari potongan kode itu dan bagaimana cara kerjanya, tetapi saya sangat menyarankan Anda untuk memperbaikinya.

Memperbarui

Untuk menguraikan tentang thisdiutamakan prototypesaya dapat menunjukkan kepada Anda sebuah contoh dan memberi tahu Anda bagaimana hal itu dapat dijelaskan, tetapi saya tidak memiliki sumber daya eksternal untuk mendukungnya.

Contohnya sangat sederhana:

var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";

var obj = new myClass;
obj.foo;     // Still contains "Foo" ...
obj.bar;     // Contains "Bar" as expected

Penjelasannya, seperti yang kita ketahui, thisrelevan dengan konteksnya. Jadi itu tidak akan ada sampai konteksnya siap. Kapan konteks siap? Saat instance baru sedang dibuat! Anda harus menebak sisanya sekarang! Ini berarti bahwa meskipun ada prototypedefinisi, tetapi thislebih masuk akal untuk diutamakan karena ini semua tentang contoh baru yang dibuat pada saat itu.

53777A
sumber
Ini adalah jawaban yang luar biasa epik! Bisakah Anda mengeditnya dan masuk ke detail lebih lanjut membandingkan dan membedakan kedua metode? Dua paragraf pertama Anda membingungkan saya tentang metode desain yang Anda maksud. Latihan Anda sangat baik! Saya tidak pernah memikirkan kekuatan prototipe seperti itu. Bisakah Anda juga memberikan contoh penggunaan kasus semi terperinci tentang kapan harus menggunakan setiap metode? Terima kasih sekali lagi, ini luar biasa.
JDillon522
@ JDillon522 Senang mendengarnya. Saya akan mencoba memperbaruinya dalam beberapa jam ke depan!
53777A
@ JDillon522 Baru saja melakukan pembaruan cepat. Semoga kali ini akan lebih jelas.
53777A
@ JDillon522 Sedikit tentang cuplikan sampel Anda ...
53777A
Contoh singleton yang bagus. Jadi saya menggunakan thiscontoh prototipe konyol karena thismengacu pada propertinya sendiri, termasuk metodenya. Saya tidak belajar yang terbaik dari membaca tentang kode, tetapi lebih dari melihat kode. ( MDN sedikit di atasnya , Object Playground (luar biasa) , dan beberapa lainnya). Bisakah Anda menunjukkan sesuatu yang menjelaskan apa yang Anda maksud tentang " thismengambil prioritas prototype"? Saya ingin melihatnya lebih dalam.
JDillon522