Apakah ada prinsip-OO yang secara praktis dapat diterapkan untuk Javascript?

79

Javascript adalah bahasa berorientasi objek berbasis prototipe tetapi dapat menjadi berbasis kelas dalam berbagai cara, baik dengan:

  • Menulis fungsi yang akan digunakan sebagai kelas sendiri
  • Gunakan sistem kelas yang bagus dalam suatu kerangka kerja (seperti mootools Class.Class )
  • Hasilkan dari Coffeescript

Pada awalnya saya cenderung menulis kode berbasis kelas dalam Javascript dan sangat bergantung padanya. Namun baru-baru ini saya telah menggunakan kerangka kerja Javascript, dan NodeJS , yang menjauh dari gagasan kelas dan lebih mengandalkan sifat dinamis dari kode seperti:

  • Pemrograman async, menggunakan dan menulis kode penulisan yang menggunakan panggilan balik / peristiwa
  • Memuat modul dengan RequireJS (agar tidak bocor ke namespace global)
  • Konsep pemrograman fungsional seperti pemahaman daftar (peta, filter, dll.)
  • Antara lain

Apa yang saya kumpulkan sejauh ini adalah bahwa sebagian besar prinsip dan pola OO yang saya baca (seperti pola SOLID dan GoF) ditulis untuk bahasa OO berbasis kelas dalam pikiran seperti Smalltalk dan C ++. Tetapi apakah ada dari mereka yang berlaku untuk bahasa berbasis prototipe seperti Javascript?

Apakah ada prinsip atau pola yang hanya spesifik untuk Javascript? Prinsip untuk menghindari panggilan balik neraka , eval jahat , atau anti-pola lainnya, dll.

Spoike
sumber

Jawaban:

116

Setelah banyak pengeditan, jawaban ini telah menjadi monster. Sebelumnya saya minta maaf.

Pertama-tama, eval()tidak selalu buruk, dan dapat membawa manfaat dalam kinerja ketika digunakan dalam evaluasi malas, misalnya. Malas-evaluasi mirip dengan lazy-loading, tetapi Anda pada dasarnya menyimpan kode Anda dalam string, dan kemudian menggunakan evalatau new Functionuntuk mengevaluasi kode. Jika Anda menggunakan beberapa trik, maka itu akan menjadi jauh lebih berguna daripada kejahatan, tetapi jika Anda tidak melakukannya, itu dapat menyebabkan hal-hal buruk. Anda dapat melihat sistem modul saya yang menggunakan pola ini: https://github.com/TheHydroImpulse/resolve.js . Resolve.js menggunakan eval alih-alih new Functionterutama untuk memodelkan CommonJS exportsdan modulevariabel yang tersedia di setiap modul, dan new Functionmembungkus kode Anda dalam fungsi anonim, meskipun, saya akhirnya membungkus setiap modul dalam suatu fungsi yang saya lakukan secara manual dalam kombinasi dengan eval.

Anda membaca lebih lanjut tentang hal itu di dua artikel berikut, yang kemudian juga merujuk pada yang pertama.

Generator Harmoni

Sekarang generator akhirnya mendarat di V8 dan dengan demikian di Node.js, di bawah bendera ( --harmonyatau --harmony-generators). Ini sangat mengurangi jumlah panggilan balik yang Anda miliki. Itu membuat menulis kode asinkron benar-benar hebat.

Cara terbaik untuk menggunakan generator adalah dengan menggunakan semacam perpustakaan aliran kontrol. Ini akan memungkinkan mengalir terus saat Anda menghasilkan di dalam generator.

Rekap / Ikhtisar:

Jika Anda tidak terbiasa dengan generator, itu adalah praktik penghentian sementara eksekusi fungsi khusus (disebut generator). Praktek ini disebut menghasilkan menggunakan yieldkata kunci.

Contoh:

function* someGenerator() {
  yield []; // Pause the function and pass an empty array.
}

Jadi, setiap kali Anda memanggil fungsi ini pertama kali, itu akan mengembalikan generator contoh baru. Ini memungkinkan Anda untuk memanggil next()objek itu untuk memulai atau melanjutkan generator.

var gen = someGenerator();
gen.next(); // { value: Array[0], done: false }

Anda akan terus menelepon nextsampai donekembali true. Ini berarti generator telah sepenuhnya menyelesaikan eksekusi, dan tidak ada lagi yieldpernyataan.

Aliran kontrol:

Seperti yang Anda lihat, mengendalikan generator tidak otomatis. Anda harus melanjutkan secara manual. Itu sebabnya control-flow libraries seperti co digunakan.

Contoh:

var co = require('co');

co(function*() {
  yield query();
  yield query2();
  yield query3();
  render();
});

Hal ini memungkinkan kemungkinan untuk menulis semuanya di Node (dan browser dengan Regenerator Facebook yang mengambil, sebagai input, kode sumber yang menggunakan generator harmoni dan membagi kode ES5 yang sepenuhnya kompatibel) dengan gaya sinkron.

Generator masih sangat baru, dan karenanya membutuhkan Node.js> = v11.2. Saat saya menulis ini, v0.11.x masih tidak stabil dan dengan demikian banyak modul asli rusak dan akan sampai v0.12, di mana API asli akan tenang.


Untuk menambah jawaban asli saya:

Saya baru-baru ini lebih memilih API yang lebih fungsional dalam JavaScript. Konvensi memang menggunakan OOP di belakang layar ketika dibutuhkan tetapi itu menyederhanakan semuanya.

Ambil contoh sistem tampilan (klien atau server).

view('home.welcome');

Jauh lebih mudah dibaca atau diikuti daripada:

var views = {};
views['home.welcome'] = new View('home.welcome');

The viewFungsi hanya memeriksa apakah pandangan yang sama sudah ada dalam peta lokal. Jika tampilan tidak ada, itu akan membuat tampilan baru dan menambahkan entri baru ke peta.

function view(name) {
  if (!name) // Throw an error

  if (view.views[name]) return view.views[name];

  return view.views[name] = new View({
    name: name
  });
}

// Local Map
view.views = {};

Sangat mendasar, bukan? Saya merasa secara dramatis menyederhanakan antarmuka publik dan membuatnya lebih mudah digunakan. Saya juga menggunakan kemampuan rantai ...

view('home.welcome')
   .child('menus')
   .child('auth')

Tower, kerangka kerja yang saya kembangkan (dengan orang lain) atau mengembangkan versi berikutnya (0.5.0) akan menggunakan pendekatan fungsional ini di sebagian besar antarmuka yang terbuka.

Beberapa orang memanfaatkan serat sebagai cara untuk menghindari "panggilan balik neraka". Ini pendekatan yang sangat berbeda untuk JavaScript, dan saya bukan penggemar berat itu, tetapi banyak kerangka kerja / platform menggunakannya; termasuk Meteor, karena mereka memperlakukan Node.js sebagai platform utas / per koneksi.

Saya lebih suka menggunakan metode abstrak untuk menghindari panggilan balik neraka. Ini mungkin menjadi rumit, tetapi sangat menyederhanakan kode aplikasi yang sebenarnya. Ketika membantu membangun kerangka TowerJS , itu memecahkan banyak masalah kami, meskipun, Anda pasti masih memiliki beberapa tingkat panggilan balik, tetapi sarangnya tidak dalam.

// app/config/server/routes.js
App.Router = Tower.Router.extend({
  root: Tower.Route.extend({
    route: '/',
    enter: function(context, next) {
      context.postsController.page(1).all(function(error, posts) {
        context.bootstrapData = {posts: posts};
        next();
      });
    },
    action: function(context, next) {
      context.response.render('index', context);
      next();
    },
    postRoutes: App.PostRoutes
  })
});

Contoh dari kami, yang saat ini sedang dikembangkan, sistem perutean dan "pengontrol", meskipun agak berbeda dari "rel-seperti" tradisional. Tapi contohnya sangat kuat dan meminimalkan jumlah panggilan balik dan membuat semuanya tampak jelas.

Masalah dengan pendekatan ini adalah bahwa semuanya disarikan. Tidak ada yang berjalan apa adanya, dan membutuhkan "kerangka kerja" di belakangnya. Tetapi jika fitur dan gaya pengkodean seperti ini diterapkan dalam suatu kerangka kerja, maka ini merupakan kemenangan besar.

Untuk pola-pola dalam JavaScript, itu benar-benar tergantung. Warisan hanya benar-benar berguna ketika menggunakan CoffeeScript, Ember, atau kerangka / infrastruktur "kelas" apa pun. Saat Anda berada di dalam lingkungan JavaScript "murni", menggunakan antarmuka prototipe tradisional berfungsi seperti pesona:

function Controller() {
    this.resource = get('resource');
}

Controller.prototype.index = function(req, res, next) {
    next();
};

Ember.js memulai, setidaknya bagi saya, menggunakan pendekatan berbeda untuk membangun objek. Alih-alih membangun setiap metode prototipe secara independen, Anda akan menggunakan antarmuka seperti modul.

Ember.Controller.extend({
   index: function() {
      this.hello = 123;
   },
   constructor: function() {
      console.log(123);
   }
});

Semua ini berbeda gaya "coding", tetapi tambahkan ke basis kode Anda.

Polimorfisme

Polimorfisme tidak banyak digunakan dalam JavaScript murni, di mana bekerja dengan pewarisan dan menyalin model "kelas" seperti membutuhkan banyak kode boilerplate.

Desain Berbasis Acara / Komponen

Model berbasis peristiwa dan berbasis komponen adalah pemenang IMO, atau yang paling mudah untuk diajak bekerja sama, terutama ketika bekerja dengan Node.js, yang memiliki komponen EventEmitter bawaan, meskipun, menerapkan emitor seperti itu sepele, itu hanya tambahan yang bagus .

event.on("update", function(){
    this.component.ship.velocity = 0;
    event.emit("change.ship.velocity");
});

Contoh saja, tapi ini model yang bagus untuk dikerjakan. Terutama dalam proyek berorientasi permainan / komponen.

Desain komponen adalah konsep yang terpisah dengan sendirinya, tetapi saya pikir itu bekerja sangat baik dalam kombinasi dengan sistem acara. Game secara tradisional dikenal untuk desain berbasis komponen, di mana pemrograman berorientasi objek hanya membawa Anda sejauh ini.

Desain berbasis komponen memiliki kegunaannya. Tergantung pada jenis sistem bangunan Anda. Saya yakin ini akan bekerja dengan aplikasi web, tetapi itu akan bekerja dengan sangat baik di lingkungan permainan, karena jumlah objek, dan sistem yang terpisah, tetapi contoh lain pasti ada.

Pola Pub / Sub

Pengikatan acara dan pub / sub serupa. Pola pub / sub benar-benar bersinar di aplikasi Node.js karena bahasa pemersatu, tetapi dapat bekerja di bahasa apa pun. Bekerja sangat baik dalam aplikasi waktu nyata, permainan, dll.

model.subscribe("message", function(event){
    console.log(event.params.message);
});

model.publish("message", {message: "Hello, World"});

Pengamat

Ini mungkin subyektif, karena beberapa orang memilih untuk menganggap pola Pengamat sebagai pub / sub, tetapi mereka memiliki perbedaan.

"Pengamat adalah pola desain di mana suatu objek (dikenal sebagai subjek) memelihara daftar objek tergantung padanya (pengamat), secara otomatis memberi tahu mereka tentang segala perubahan yang terjadi." - Pola Pengamat

Pola pengamat adalah langkah di luar sistem pub / sub khas. Objek memiliki hubungan yang ketat atau metode komunikasi satu sama lain. Objek "Subjek" akan menyimpan daftar tanggungan "Pengamat". Subjek akan membuat pengamatnya tetap mutakhir.

Pemrograman Reaktif

Pemrograman reaktif adalah konsep yang lebih kecil, lebih tidak dikenal, terutama dalam JavaScript. Ada satu kerangka / pustaka (yang saya tahu) yang memperlihatkan API yang mudah untuk digunakan menggunakan "pemrograman reaktif" ini.

Sumber daya pada pemrograman reaktif:

Pada dasarnya, ini memiliki satu set data yang disinkronkan (baik itu variabel, fungsi, dll.).

 var a = 1;
 var b = 2;
 var c = a + b;

 a = 2;

 console.log(c); // should output 4

Saya percaya pemrograman reaktif sangat tersembunyi, terutama dalam bahasa imperatif. Ini adalah paradigma pemrograman yang luar biasa kuat, terutama di Node.js. Meteor telah menciptakan mesin reaktif sendiri di mana kerangka dasarnya didasarkan. Bagaimana reaktivitas Meteor bekerja di belakang layar? adalah gambaran bagus tentang cara kerjanya secara internal.

Meteor.autosubscribe(function() {
   console.log("Hello " + Session.get("name"));
});

Ini akan mengeksekusi secara normal, menampilkan nilai name, tetapi jika kita mengubahnya

Session.set ('name', 'Bob');

Ini akan menampilkan ulang tampilan console.log Hello Bob. Contoh dasar, tetapi Anda dapat menerapkan teknik ini untuk model dan transaksi data waktu nyata. Anda dapat membuat sistem yang sangat kuat di belakang protokol ini.

Meteor ...

Pola reaktif dan pola pengamat sangat mirip. Perbedaan utama adalah bahwa pola pengamat biasanya menggambarkan aliran data dengan seluruh objek / kelas vs pemrograman reaktif menggambarkan aliran data ke properti tertentu.

Meteor adalah contoh yang bagus dari pemrograman reaktif. Itu runtime sedikit rumit karena kurangnya JavaScript dari peristiwa perubahan nilai asli (Harmony proksi mengubahnya). Kerangka kerja sisi klien lainnya, Ember.js dan AngularJS juga menggunakan pemrograman reaktif (hingga batas tertentu).

Dua kerangka kerja berikutnya menggunakan pola reaktif yang paling menonjol pada templatnya (yaitu memperbarui otomatis). Angular.js menggunakan teknik pemeriksaan kotor sederhana. Saya tidak akan menyebut pemrograman reaktif ini persis, tetapi dekat, karena pemeriksaan kotor tidak real-time. Ember.js menggunakan pendekatan yang berbeda. Penggunaan set()dan get()metode Ember yang memungkinkan mereka untuk segera memperbarui nilai-nilai yang tergantung. Dengan runloop mereka sangat efisien dan memungkinkan nilai yang lebih tergantung, di mana sudut memiliki batas teoritis.

Janji

Bukan perbaikan untuk callback, tetapi menghapus lekukan, dan menjaga fungsi bersarang ke minimum. Itu juga menambahkan beberapa sintaks yang bagus untuk masalah.

fs.open("fs-promise.js", process.O_RDONLY).then(function(fd){
  return fs.read(fd, 4096);
}).then(function(args){
  util.puts(args[0]); // print the contents of the file
});

Anda juga bisa menyebarkan fungsi panggilan balik sehingga tidak sejajar, tapi itu keputusan desain lainnya.

Pendekatan lain adalah dengan menggabungkan acara dan janji di mana Anda akan memiliki fungsi untuk mengirimkan acara secara tepat, maka fungsi fungsional nyata (yang memiliki logika nyata di dalamnya) akan mengikat ke acara tertentu. Anda kemudian akan melewati metode dispatcher di dalam setiap posisi panggilan balik, meskipun, Anda harus bekerja di luar beberapa ketegaran yang akan terlintas dalam pikiran, seperti parameter, mengetahui fungsi mana untuk mengirim ke, dll ...

Fungsi Fungsi Tunggal

Alih-alih memiliki kekacauan panggilan balik yang sangat besar, pertahankan satu fungsi untuk satu tugas, dan lakukan tugas itu dengan baik. Terkadang Anda bisa maju sendiri dan menambahkan lebih banyak fungsi dalam setiap fungsi, tetapi tanyakan pada diri sendiri: Bisakah ini menjadi fungsi independen? Beri nama fungsinya, dan ini membersihkan lekukan Anda dan, sebagai hasilnya, membersihkan masalah neraka panggil balik.

Pada akhirnya, saya sarankan mengembangkan, atau menggunakan "kerangka" kecil, pada dasarnya hanya tulang punggung untuk aplikasi Anda, dan luangkan waktu untuk membuat abstraksi, memutuskan sistem berbasis acara, atau "banyak modul kecil yang sistem "independen. Saya telah bekerja dengan beberapa proyek Node.js di mana kode itu sangat berantakan dengan panggilan balik neraka khususnya, tetapi juga kurangnya pemikiran sebelum mereka mulai coding. Luangkan waktu Anda untuk memikirkan berbagai kemungkinan yang berbeda dalam hal API, dan sintaksis.

Ben Nadel telah membuat beberapa posting blog yang sangat bagus tentang JavaScript dan beberapa pola yang cukup ketat dan canggih yang dapat bekerja dalam situasi Anda. Beberapa postingan bagus yang akan saya tekankan:

Inversi-of-Control

Meskipun tidak persis terkait dengan panggilan balik neraka, ini dapat membantu Anda secara keseluruhan arsitektur, terutama dalam unit test.

Dua sub-versi utama inversi-of-control adalah Dependency Injection dan Service Locator. Saya menemukan Service Locator sebagai yang termudah dalam JavaScript, bukan Injeksi Ketergantungan. Mengapa? Terutama karena JavaScript adalah bahasa yang dinamis dan tidak ada pengetikan statis. Java dan C #, antara lain, "dikenal" untuk injeksi dependensi karena Anda dapat mendeteksi jenis, dan mereka telah dibangun di antarmuka, kelas, dll ... Ini membuat semuanya cukup mudah. Anda dapat, bagaimanapun, menciptakan kembali fungsi ini dalam JavaScript, meskipun, itu tidak akan menjadi identik dan sedikit meretas, saya lebih suka menggunakan pelacak layanan di dalam sistem saya.

Setiap jenis inversi-of-control akan secara dramatis memisahkan kode Anda menjadi modul terpisah yang dapat diejek atau dipalsukan kapan saja. Dirancang versi kedua dari mesin rendering Anda? Luar biasa, ganti saja antarmuka lama dengan yang baru. Penelusur layanan sangat menarik dengan Proksi Harmony baru, meskipun, hanya dapat digunakan secara efektif dalam Node.js, ia menyediakan API yang lebih baik, daripada menggunakan Service.get('render');dan sebagai gantinya Service.render. Saat ini saya sedang mengerjakan sistem semacam itu: https://github.com/TheHydroImpulse/Ettore .

Meskipun kurangnya pengetikan statis (pengetikan statis menjadi alasan yang memungkinkan untuk penggunaan efektif dalam injeksi dependensi di Java, C #, PHP - Ini bukan pengetikan statis, tetapi memiliki pengetikan jenis.) Mungkin dipandang sebagai titik negatif, Anda dapat pasti mengubahnya menjadi poin yang kuat. Karena semuanya dinamis, Anda dapat merekayasa sistem statis "palsu". Dalam kombinasi dengan pencari lokasi layanan, Anda dapat membuat setiap komponen / modul / kelas / instance diikat ke suatu jenis.

var Service, componentA;

function Manager() {
  this.instances = {};
}

Manager.prototype.get = function(name) {
  return this.instances[name];
};

Manager.prototype.set = function(name, value) {
  this.instances[name] = value;
};

Service = new Manager();
componentA = {
  type: "ship",
  value: new Ship()
};

Service.set('componentA', componentA);

// DI
function World(ship) {
  if (ship === Service.matchType('ship', ship))
    this.ship = new ship();
  else
    throw Error("Wrong type passed.");
}

// Use Case:
var worldInstance = new World(Service.get('componentA'));

Contoh sederhana. Untuk dunia nyata, penggunaan yang efektif, Anda harus membawa konsep ini lebih jauh, tetapi ini dapat membantu memisahkan sistem Anda jika Anda benar-benar menginginkan injeksi ketergantungan tradisional. Anda mungkin perlu mengutak-atik konsep ini sedikit. Saya belum terlalu memikirkan contoh sebelumnya.

Model-View-Controller

Pola paling jelas, dan paling banyak digunakan di web. Beberapa tahun yang lalu, JQuery sangat populer, dan karena itu, plugin JQuery lahir. Anda tidak memerlukan kerangka kerja lengkap di sisi klien, cukup gunakan jquery dan beberapa plugin.

Sekarang, ada perang kerangka JavaScript sisi klien yang besar. Sebagian besar menggunakan pola MVC, dan mereka semua menggunakannya secara berbeda. MVC tidak selalu menerapkan hal yang sama.

Jika Anda menggunakan antarmuka prototipe tradisional, Anda mungkin kesulitan mendapatkan gula sintaksis atau API yang bagus ketika bekerja dengan MVC, kecuali jika Anda ingin melakukan pekerjaan manual. Ember.js menyelesaikan ini dengan membuat sistem "class" / object ". Pengontrol mungkin terlihat seperti:

 var Controller = Ember.Controller.extend({
      index: function() {
        // Do something....
      }
 });

Sebagian besar pustaka sisi klien juga memperluas pola MVC dengan memperkenalkan view-helper (menjadi tampilan) dan templat (menjadi tampilan).


Fitur JavaScript Baru:

Ini hanya akan efektif jika Anda menggunakan Node.js, namun demikian, ini sangat berharga. Pembicaraan di NodeConf oleh Brendan Eich ini menghadirkan beberapa fitur baru yang keren. Sintaks fungsi yang diusulkan, dan terutama pustaka Task.js js.

Ini mungkin akan memperbaiki sebagian besar masalah dengan fungsi bersarang dan akan membawa kinerja yang sedikit lebih baik karena kurangnya fungsi overhead.

Saya tidak terlalu yakin apakah V8 mendukung ini secara asli, terakhir saya memeriksa Anda perlu mengaktifkan beberapa flag, tetapi ini berfungsi di port Node.js yang menggunakan SpiderMonkey .

Sumber Daya Ekstra:

Daniel
sumber
2
Langgan yang bagus. Saya pribadi tidak menggunakan untuk MV? perpustakaan. Kami memiliki semua yang kami butuhkan untuk mengatur kode kami untuk aplikasi yang lebih besar dan lebih kompleks. Mereka semua mengingatkan saya terlalu banyak pada Java dan C # mencoba untuk melemparkan berbagai tirai sendiri atas apa yang sebenarnya terjadi dalam komunikasi server-client. Kami mendapat DOM. Kami mendapat delegasi acara. Kami mendapat OOP. Saya dapat mengikat acara saya sendiri dengan perubahan data tyvm.
Erik Reppen
2
"Alih-alih memiliki kekacauan panggilan balik yang sangat besar, simpan satu fungsi untuk satu tugas, dan lakukan tugas itu dengan baik." - Puisi.
CuriousWebDeveloper
1
Javascript ketika melewati usia yang sangat gelap di awal hingga pertengahan 2000-an ketika sedikit yang mengerti bagaimana menulis aplikasi besar menggunakannya. Seperti kata @ErikReppen, jika Anda menemukan aplikasi JS Anda terlihat seperti aplikasi Java atau C #, Anda melakukannya dengan salah.
backpackcoder
3

Menambahkan ke jawaban Daniels:

Nilai / komponen yang dapat diobservasi

Gagasan ini dipinjam dari kerangka kerja MVVM Knockout.JS ( ko.observable ), dengan gagasan bahwa nilai dan objek dapat menjadi subyek yang dapat diobservasi, dan sekali perubahan terjadi dalam satu nilai atau objek, ia akan secara otomatis memperbarui semua pengamat. Ini pada dasarnya adalah pola pengamat yang diimplementasikan dalam Javascript, dan sebaliknya bagaimana sebagian besar pub / sub framework diimplementasikan, "kunci" adalah subjek itu sendiri, bukan objek yang arbitrer.

Penggunaannya adalah sebagai berikut:

// the subjects
// plain old javascript object with observable values
var shipComponent = {
    velocity : observable(0)
};

// the observer, a player user interface
// implemented with revealing module pattern
var playerUi = (function(ship) {

  var module = {
    setVelocity: function (x) { 
      // ... sets the velocity on the player user interface
    },

    // only called once
    init: function() {

      // subscribe to changes on the velocity value
      // using the module's function as callback
      module.velocity.onChange(playerUi.setVelocity);
    }
  };

  return module;
})(shipComponent).init();

// the player ui will change when the velocity value is changed
shipComponent.velocity.set(10);

Idenya adalah bahwa pengamat biasanya tahu di mana subjek berada dan bagaimana berlangganannya. Keuntungan dari ini daripada pub / sub terlihat jika Anda harus banyak mengubah kode karena lebih mudah untuk menghapus subjek dari sebagai langkah refactoring. Maksud saya ini karena sekali Anda menghapus subjek, semua orang yang bergantung padanya akan gagal. Jika kode gagal dengan cepat maka Anda tahu di mana harus menghapus referensi yang tersisa. Ini berbeda dengan subjek yang benar-benar dipisahkan (seperti dengan kunci string dalam pola pub / sub) dan memiliki peluang lebih tinggi untuk tetap berada dalam kode terutama jika kunci dinamis digunakan dan pemrogram pemeliharaan tidak menyadarinya (mati kode dalam pemrograman pemeliharaan adalah masalah yang mengganggu).

Dalam pemrograman game, ini mengurangi kebutuhan Ye Olde pola putaran pembaruan dan lebih ke dalam evented / reaktif idiom pemrograman, karena begitu ada sesuatu yang berubah subjek akan secara otomatis memperbarui semua pengamat pada perubahan, tanpa harus menunggu loop pembaruan untuk mengeksekusi. Ada kegunaan untuk loop pembaruan (untuk hal-hal yang perlu disinkronkan dengan waktu permainan yang berlalu), tetapi kadang-kadang Anda hanya tidak ingin mengacaukannya ketika komponen itu sendiri dapat memperbarui diri secara otomatis dengan pola ini.

Implementasi aktual dari fungsi yang dapat diamati sebenarnya sangat mudah untuk ditulis dan dipahami (terutama jika Anda tahu cara menangani array dalam javascript dan pola pengamat ):

var observable = function(v) {
    var val = v, subscribers = [];

    // the observable object,
    // as revealing module
    var output = {

        // subscribes to event
        onChange : function(func) {
            // idiomatic JS to add object to the
            // subscribers array
            subscribers.push(func);

            return output: // enables chaining
        },

        // the method that changes the observable object
        // and emits the event
        set : function(v) {
            var i;
            val = v;
            for (i = 0, i < subscribers.length; i++) {
                // this is hardly fault tolerant but as long
                // as subscribers are functions it'll work
                subscribers[i](v);
            }

            return output;
        }

    };

    return output;
};

Saya telah membuat implementasi objek yang dapat diamati di JsFiddle yang melanjutkan ini dengan mengamati komponen dan mampu menghapus pelanggan. Jangan ragu untuk bereksperimen dengan JsFiddle.

Spoike
sumber