Javascript için pratikte uygulanabilir olan herhangi bir OO prensibi var mı?


79

Javascript, prototip tabanlı nesne yönelimli bir dildir ancak aşağıdaki yöntemlerden biriyle çeşitli şekillerde sınıf tabanlı olabilir:

  • Sınıf olarak kullanılacak işlevleri kendiniz yazmak
  • Şık bir sınıf sistemi bir çerçevede kullanın (örneğin, mootools Class.Class gibi )
  • Coffeescript'ten oluşturun

Başlangıçta Javascript’te sınıf tabanlı bir kod yazmam ve yoğun bir şekilde güvenmem gerekti. Ancak son zamanlarda Javascript çerçevelerini ve bu sınıf kavramından uzaklaşan ve aşağıdaki gibi kodun dinamik yapısına dayanan NodeJS'yi kullanıyorum :

  • Zaman uyumsuz programlama, geri çağırmalar / olaylar kullanan yazma kodu kullanma ve yazma
  • RequireJS ile modüller yükleme (böylece küresel ad alanına sızıntı yapmazlar)
  • Liste anlama (harita, filtre vb.) Gibi fonksiyonel programlama kavramları
  • Diğer şeylerin yanı sıra

Şimdiye kadar topladığım şey, okuduğum OO ilkelerinin ve modellerinin (SOLID ve GoF kalıpları gibi) Smalltalk ve C ++ gibi akılda kalan sınıf tabanlı OO dilleri için yazılmış olmasıdır. Ancak Javascript gibi prototip tabanlı bir dil için geçerli herhangi biri var mı?

Javascript’e özgü ilkeler veya desenler var mı? İlkeler önlemek için geri arama cehennem , şeytan eval vb veya herhangi bir başka anti-desen

Yanıtlar:


116

Birçok düzenlemeden sonra, bu cevap uzun süren bir canavar oldu. Şimdiden özür dilerim.

Her şeyden önce, eval()her zaman kötü değildir ve örneğin tembel değerlendirmede kullanıldığında performanstan fayda sağlayabilir. Tembel değerlendirme tembel yüklemeye benzer, ancak temel olarak kodunuzu dizelerde saklar ve sonra kodu değerlendirmek için evalveya new Functionkullanırsınız. Bazı hileler kullanırsanız, o zaman kötülükten çok daha kullanışlı hale gelecektir, ancak kullanmazsanız, kötü şeylere yol açabilir. Bu modeli kullanan modül sistemime bakabilirsiniz: https://github.com/TheHydroImpulse/resolve.js . Resolve.js new Functionöncelikle her bir modüldeki CommonJS exportsve moduledeğişkenleri modellemek yerine eval kullanır ve new Functionkodunuzu anonim bir işlev içinde sarar, ancak her modülü eval ile birlikte yaptığım bir işlevde tamamlamayı bırakarım.

Bu konuda aşağıdaki iki makalede daha fazlasını okudunuz, daha sonra birincisine de değiniyoruz.

Harmony Jeneratörleri

Şimdi, jeneratörler nihayet V8'e ve dolayısıyla Node.js'ye bir bayrak ( --harmonyveya --harmony-generators) altına girdiler . Bunlar, sahip olduğunuz geri arama miktarını büyük ölçüde azaltır. Zaman uyumsuz kod yazmayı gerçekten harika kılar.

Jeneratörleri kullanmanın en iyi yolu bir çeşit kontrol-akış kütüphanesi kullanmaktır. Bu, jeneratörler içinde verdiğiniz gibi çalışmaya devam etmek için akmaya olanak sağlayacaktır.

Recap / Genel Bakış:

Jeneratörlere yabancıysanız, özel fonksiyonların (jeneratör olarak adlandırılan) yürütülmesini duraklatma uygulamasıdır. Bu uygulamaya anahtar kelime kullanılarak verim denir yield.

Örnek:

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

Böylece, bu fonksiyonu ilk ne zaman çağırırsanız, yeni bir jeneratör örneği döndürür. Bu next(), jeneratörü başlatmak veya devam ettirmek için o nesneyi çağırmanızı sağlar .

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

Sen aramaya devam ediyorum nextkadar donegetiri true. Bu, jeneratörün yürütmesini tamamen bitirdiği ve daha fazla yieldaçıklama olmadığı anlamına gelir .

Kontrol akışı:

Gördüğünüz gibi, jeneratörlerin kontrolü otomatik değildir. Her birine manuel olarak devam etmeniz gerekiyor. Bu yüzden co gibi kontrol akışı kütüphaneleri kullanılır.

Örnek:

var co = require('co');

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

Bu, Düğüm'deki her şeyi (ve, uyumlu olarak üreteçleri kullanan ve tam uyumlu ES5 kodunu tam olarak dağıtan ES5 kodunu dağıtan kaynak kodunu alan Facebook Regenerator ile tarayıcı) yazabilme imkanı sağlar .

Jeneratörler hala oldukça yeni ve bu nedenle Node.js> = v11.2 gerektiriyor. Bunu yazarken, v0.11.x hala dengesiz ve bu nedenle birçok yerel modül bozuldu ve yerel API'nin sakinleşeceği v0.12'ye kadar olacak.


Orijinal cevabımı eklemek için:

Geçenlerde JavaScript’te daha işlevsel bir API tercih ettim. Kongre gerektiğinde perde arkasında OOP kullanıyor ancak her şeyi basitleştiriyor.

Örneğin bir görüntü sistemi (istemci veya sunucu) düşünün.

view('home.welcome');

Okumak veya takip etmek çok daha kolaydır:

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

viewAynı görünüm zaten yerel bir haritası varsa fonksiyon sadece denetler. Görünüm yoksa, yeni bir görünüm oluşturur ve haritaya yeni bir giriş ekler.

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 = {};

Son derece basit, değil mi? Kamusal arayüzü çarpıcı biçimde basitleştirdiğini ve kullanımını kolaylaştırdığını buluyorum. Ayrıca zincir yetenek kullanıyorum ...

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

Tower, geliştirdiğim (başkasıyla birlikte) veya bir sonraki sürümü (0.5.0) geliştirdiğim bir çerçeve, bu işlevsel yaklaşımı ortaya çıkaran arayüzlerde kullanacak.

Bazı insanlar "geri arama cehennemi" ni önlemenin bir yolu olarak elyaflardan yararlanır. JavaScript için oldukça farklı bir yaklaşım ve ben onun çok büyük bir hayranı değilim, ancak birçok çerçeve / platform bunu kullanıyor; Meteor dahil, Node.js'i bir iş parçacığı / bağlantı platformu olarak gördükleri için.

Geri arama cehennemini önlemek için soyutlanmış bir yöntem kullanmayı tercih ederim. Bu hantal hale gelebilir, ancak gerçek uygulama kodunu büyük ölçüde basitleştirir. TowerJS çerçevesini oluşturmaya yardımcı olurken , sorunlarımızın çoğunu çözdü, ancak hala belli düzeyde bir geri çağırma düzeyine sahip olacaksınız, ancak yuvalama derin değil.

// 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
  })
});

Halen geliştirilmekte olan, rotalama sistemi ve "denetleyicilere" bir örnek, geleneksel "ray benzeri" den oldukça farklı olsa da. Ancak örnek son derece güçlüdür ve geri aramaların miktarını en aza indirir ve olayları oldukça belirgin hale getirir.

Bu yaklaşımla ilgili sorun, her şeyin soyutlanmasıdır. Hiçbir şey olduğu gibi çalışamaz ve arkasında bir "çerçeve" gerektirmez. Ancak, bu tür özellikler ve kodlama stili bir çerçeve içinde uygulanırsa, o zaman büyük bir kazançtır.

JavaScript'teki desenler için, dürüstçe bağlıdır. Kalıtım, yalnızca CoffeeScript, Ember veya herhangi bir "sınıf" çerçevesini / altyapısını kullanırken gerçekten yararlıdır. "Saf" bir JavaScript ortamındaysanız, geleneksel prototip arayüzünü kullanmak bir cazibe işlevi görür:

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

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

Ember.js, en azından benim için, nesneleri inşa etmek için farklı bir yaklaşım kullanmaya başladı. Her prototip yöntemi bağımsız olarak oluşturmak yerine, modül benzeri bir arabirim kullanırsınız.

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

Bütün bunlar farklı "kodlama" stilleridir ancak kod tabanınıza ekleyin.

Polimorfizm

Polimorfizm, kalıtımsal çalışma ve "sınıf" benzeri bir modelin kopyalanması için çok fazla kodlama kodu gerektiren saf JavaScript'te yaygın olarak kullanılmaz.

Etkinlik / Bileşen Tabanlı Tasarım

Etkinlik temelli ve Bileşen temelli modeller kazananlar IMO'dur, ya da özellikle yerleşik bir EventEmitter bileşenine sahip olan Node.js ile çalışırken, bu tür yayınlayıcıları uygulamak önemsiz olmakla birlikte, çalışılması en kolay olanıdır. .

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

Sadece bir örnek, ama çalışmak için güzel bir model. Özellikle oyun / bileşen odaklı bir projede.

Komponent tasarımı ayrı bir konsepttir, ancak etkinlik sistemlerine kombinasyon halinde oldukça iyi çalıştığını düşünüyorum. Oyunlar geleneksel olarak, nesne yönelimli programlamanın sizi yalnızca şimdiye kadar götürdüğü, bileşen tabanlı tasarımlarla bilinir.

Bileşen tabanlı tasarımın kullanımları vardır. Binanızın ne tür bir sistem olduğuna bağlı. Web uygulamaları ile çalışacağına eminim, ancak oyun ortamında, nesne sayısı ve ayrı sistemler nedeniyle oldukça iyi çalışıyordu, ancak başka örnekler de var.

Pub / Alt Desen

Olay bağlama ve pub / sub benzer. Pub / sub şablonu, birleştirici dil nedeniyle Node.js uygulamalarında gerçekten parlıyor, ancak herhangi bir dilde çalışabiliyor. Gerçek zamanlı uygulamalarda, oyunlarda vb. Son derece iyi çalışır.

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

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

Gözlemci

Bazıları Gözlemci modelini pub / sub olarak düşünmeyi seçtikleri için bu öznel olabilir, ancak farklılıkları vardır.

“Gözlemci, bir nesnenin (özne olarak bilinen) nesneye bağlı olarak bir nesne listesini (gözlemciler) tuttuğu ve durumdaki değişiklikleri otomatik olarak bildiren bir tasarım desenidir.” - Gözlemci Deseni

Gözlemci modeli, tipik pub / alt sistemlerin ötesinde bir adımdır. Nesnelerin birbirleriyle sıkı ilişkileri veya iletişim yöntemleri vardır. Bir "Nesne" nesnesi, "Gözlemciler" bağımlılarının bir listesini tutar. Konu gözlemcilerini güncel tutacaktır.

Reaktif Programlama

Reaktif programlama, özellikle JavaScript'te daha küçük, daha bilinmeyen bir kavramdır. Bu "reaktif programlamayı" kullanmak için API ile kolay bir çalışma sergileyen bir çerçeve / kütüphane (bildiğim kadarıyla) var.

Reaktif programlama ile ilgili kaynaklar:

Temel olarak, bir dizi senkronizasyon verisine sahip (değişkenler, fonksiyonlar vb.).

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

 a = 2;

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

Reaktif programlamanın, özellikle zorunlu dillerde, oldukça gizli olduğuna inanıyorum. Şaşırtıcı derecede güçlü bir programlama paradigması, özellikle de Node.js. Meteor , çerçevenin temelde dayandığı kendi reaktif motorunu yarattı. Meteor'un reaktivitesi perde arkasında nasıl çalışıyor? dahili olarak nasıl çalıştığına dair harika bir genel bakış.

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

Bu, normal olarak yürütülür, değerini gösterir name, ancak değiştirirsek

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

Konsol göstergesini tekrar gösterecek Hello Bob. Temel bir örnek, ancak bu tekniği gerçek zamanlı veri modelleri ve işlemlere uygulayabilirsiniz. Bu protokolün arkasında son derece güçlü sistemler oluşturabilirsiniz.

Meteor en ...

Reaktif model ve Gözlemci model oldukça benzerdir. Asıl fark, gözlemci modelinin genel olarak tüm nesneler / sınıflarla veri akışını tanımlamasıdır - reaktif programlama, bunun yerine belirli özelliklere veri akışını tanımlar.

Meteor reaktif programlama için harika bir örnek. JavaScript'in yerel değer değişikliği olaylarının olmayışı nedeniyle çalışma zamanı biraz karışıktır (Harmony proxy'ler bunu değiştirir). Diğer istemci tarafındaki çerçeveler, Ember.js ve AngularJS de reaktif programlamadan faydalanmaktadır (bir dereceye kadar).

Daha sonraki iki çerçeve reaktif örüntüyü en çok şablonlarında kullanır (ki otomatik güncelleme). Angular.js basit bir kirli kontrol tekniği kullanır. Buna tam olarak reaktif programlama demezdim, ama kirli kontrol gerçek zamanlı olmadığı için yakın. Ember.js farklı bir yaklaşım kullanıyor. Köz kullanımı set()ve get()bağlı değerleri hemen güncellemelerini sağlayan yöntemler. Onların runloopları ile oldukça verimlidir ve açının teorik bir limitinin olduğu yerlerde daha fazla bağımlı değere izin verir.

sözler

Geri aramalar için bir düzeltme değildir, ancak bazı girintileri ortadan kaldırır ve iç içe geçmiş işlevleri en aza indirir. Aynı zamanda soruna bazı güzel sözdizimi ekler.

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
});

Geri arama işlevlerini aynı zamanda yayılmayacak şekilde dağıtabilirsiniz, ancak bu başka bir tasarım kararıdır.

Bir başka yaklaşım, olayları birleştirmek ve olayları uygun bir şekilde gönderme işlevinin nerede olacağına dair sözleri birleştirmek olacaktır, daha sonra gerçek işlevsel işlevler (içinde gerçek mantığı olan kişiler) belirli bir olaya bağlanır. Daha sonra gönderici yöntemini her geri arama pozisyonunun içinden geçirirsiniz, ancak, hangi işlevlerin gönderileceğini bilmek gibi parametreler gibi akla gelebilecek bazı garip şeyleri çözmeniz gerekir.

Tek İşlevli İşlev

Çok büyük bir geri arama cehennemi olmak yerine, tek bir işlevi tek bir görevde tutun ve bu görevi iyi yapın. Bazen kendinize öne geçebilir ve her fonksiyona daha fazla fonksiyonellik ekleyebilirsiniz, ancak kendinize sorun: Bu bağımsız bir fonksiyon olabilir mi? İşleve bir ad verin ve bu girintinizi temizler ve sonuç olarak geri arama cehennemi sorununu temizler.

Sonunda, uygulamanız için temelde yalnızca bir omurga geliştirmeyi veya küçük bir "çerçeve" kullanmanızı öneririm ve soyutlamalar yapmak, olaya dayalı bir sisteme karar vermek veya "küçük modüller yükü" almak için zaman ayırın. bağımsız "sistem. Kodun özellikle geri arama cehennemi ile çok karışık olduğu, ancak kodlamaya başlamadan önce düşünce eksikliğinin olduğu Node.js projeleriyle çalıştım. API ve sözdizimi açısından farklı olasılıkları düşünmek için zaman ayırın.

Ben Nadel , JavaScript hakkında gerçekten iyi blog yazıları ve durumunuzda işe yarayabilecek oldukça katı ve gelişmiş modeller yaptı. Vurgulayacağım bazı iyi yazılar:

Ters çevirme-of-Control

Tam olarak geri arama cehennemi ile ilgili olmasa da, özellikle birim testlerinde genel mimariye yardımcı olabilir.

Kontrolün inversiyonunun iki ana alt versiyonu Bağımlılık Enjeksiyonu ve Servis Bulucu'dur. Bağımlılık Enjeksiyonunun aksine, Hizmet Bulucu'yu JavaScript içinde en kolay buluyorum. Neden? Temel olarak, JavaScript dinamik bir dil olduğundan ve statik yazı olmadığından. Java ve C #, diğerleri arasında, bağımlılık enjeksiyonuyla "tanınır" çünkü türleri tespit edebiliyorsunuz ve arayüzler, sınıflar vb. Bununla birlikte, bu işlevselliği JavaScript'te yeniden oluşturabilirsiniz, ancak aynı ve biraz rahatsız edici olmayacak, sistemlerimde bir servis bulucu kullanmayı tercih ediyorum.

Herhangi bir kontrolün tersine çevrilmesi, kodunuzu istediğiniz zaman alay edilebilecek veya taklit edilebilecek ayrı modüllere dönüştürür. İşleme motorunuzun ikinci bir versiyonunu mu tasarladınız? Müthiş, sadece yenisi için eski arayüzü yerine. Hizmet konumlandırıcıları özellikle yeni Harmony Proxies ile ilgi çekici olsa da, yalnızca Node.js içinde etkin bir şekilde kullanılabiliyorsa, kullanmak Service.get('render');yerine ve yerine daha iyi bir API sağlar Service.render. Şu anda bu tür bir sistem üzerinde çalışıyorum: https://github.com/TheHydroImpulse/Ettore .

Statik yazma eksikliği (statik yazma, Java, C #, PHP bağımlılık enjeksiyonunda etkili kullanımlar için olası bir nedendir, ancak statik değil, ancak tip ipuçlarına sahiptir.) Olumsuz bir nokta olarak bakılabilir. kesinlikle güçlü bir noktaya çevirin. Her şey dinamik olduğu için "sahte" statik bir sistem oluşturabilirsiniz. Servis bulucu ile birlikte, her bir bileşen / modül / sınıf / örnek bir türe bağlı olabilir.

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'));

Basit bir örnek. Gerçek bir dünya için, etkili bir kullanım için, bu konsepti daha da ileri götürmeniz gerekir, ancak gerçekten geleneksel bağımlılık enjeksiyonunu istiyorsanız, sisteminizin ayrıştırılmasına yardımcı olabilir. Bu konsept ile biraz uğraşmanız gerekebilir. Önceki örneğe çok fazla düşünmedim.

Model-View-Controller

En belirgin desen ve web üzerinde en çok kullanılanlar. Birkaç yıl önce, JQuery tüm öfke ve böylece, JQuery eklentileri doğdu. Müşteri tarafında tam bir çerçeveye ihtiyacınız yoktu, sadece jquery ve birkaç eklenti kullanın.

Şimdi, büyük bir müşteri tarafı JavaScript çerçeve savaşı var. Bunların çoğu MVC paternini kullanıyor ve hepsi farklı kullanıyor. MVC her zaman aynı şekilde uygulanmaz.

Geleneksel prototip arayüzleri kullanıyorsanız, bazı el işi yapmak istemediğiniz sürece, MVC ile çalışırken sözdizimsel bir şeker veya hoş bir API almakta zorlanabilirsiniz. Ember.js bunu bir "class" / object "sistemi yaratarak çözer.

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

Çoğu müşteri tarafı kitaplığı, MVC şablonunu, görünüm yardımcıları (görünüm olma) ve şablonlar (görünüm olma) tanıtarak genişletir.


Yeni JavaScript Özellikleri:

Bu yalnızca Node.js kullanıyorsanız etkili olacaktır, ancak yine de paha biçilmezdir. NodeConf'ta Brendan Eich'in bu konuşması bazı harika yeni özellikler getiriyor. Önerilen işlev sözdizimi ve özellikle Task.js js kütüphanesi.

Bu muhtemelen işlev yerleştirme ile ilgili sorunların çoğunu çözecek ve işlev yükü eksikliği nedeniyle biraz daha iyi performans getirecektir.

V8'in bunu yerel olarak destekleyip desteklemediğinden emin değilim, en son bazı bayrakları etkinleştirmek için gerekli olduğunu kontrol ettim, ancak bu, SpiderMonkey kullanan bir Node.js bağlantı noktasında çalışıyor .

Ekstra Kaynaklar:


2
Güzel yazı. MV'yi şahsen kullanmıyorum? kütüphaneler. Daha büyük ve daha karmaşık uygulamalar için kodumuzu düzenlemek için gereken her şeye sahibiz. Hepsi bana çok fazla Java ve C # 'yi, sunucu-müşteri iletişiminde olanların üzerine kendi çeşitli saçma perdelerini atmaya çalışırken hatırlatıyor. Bir DOM var. Etkinlik heyeti aldık. OOP var. Kendi olaylarımı tyvm veri değişikliklerine bağlayabilirim.
Erik Reppen

2
"Çok büyük bir geri arama cehennemi olmak yerine, tek bir işlevi tek bir görevde tutun ve bu görevi iyi yapın." - Şiir.
CuriousWebDeveloper

1
Javascript çok karanlık bir çağın başlarında 2000'li yılların ortalarından ortalarına kadar ne zaman çok az kişi tarafından büyük uygulamalar yazılacağını anladığında. @ErikReppen'ın dediği gibi, eğer bir Java veya C # uygulaması gibi görünen JS uygulamasını bulursanız, yanlış yaparsınız.
backpackcoder

3

Daniels cevabına ekleme:

Gözlenebilir değerler / bileşenler

Bu fikir, MVVM çerçevesi Knockout.JS'den ( ko.observable ) ödünç verilir , değerler ve nesnelerin gözlemlenebilir konular olabileceği düşüncesiyle ve değişiklik bir değer veya nesnede gerçekleştiğinde, tüm gözlemcileri otomatik olarak güncelleyecektir. Temel olarak Javascript'te uygulanan gözlemci modelidir ve bunun yerine çoğu pub / alt çerçevenin nasıl uygulandığına "anahtar", rastgele bir nesne yerine konunun kendisidir.

Kullanım aşağıdaki gibidir:

// 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);

Buradaki fikir gözlemcilerin genellikle konunun nerede olduğunu ve ona nasıl abone olduğunu bilmeleridir. Bu, pub / sub yerine bunun avantajı, denemeleri yeniden düzenleme adımı olarak çıkarmak daha kolay olduğu için, kodu çok değiştirmek zorunda kalırsanız fark edilir. Bunu kastettim, çünkü bir konuyu bir kez çıkardığınızda, bağımlı olan herkes başarısız olur. Kod hızlı bir şekilde başarısız olursa, kalan referansları nereye kaldıracağınızı bilirsiniz. Bu tamamen ayrılan öznenin (pub / sub düzeninde bir dize tuşuyla olduğu gibi) tam tersidir ve özellikle dinamik anahtarlar kullanılmışsa ve bakım programcısı bunun farkında olmamışsa kodda kalma şansı yüksektir. bakım programlamasında kod can sıkıcı bir sorundur).

Oyun programlamada, bu ihtiyacını azaltır ye olde şey değiştirilir kısa sürede konu otomatik değişim üzerindeki tüm gözlemciler güncellenir çünkü güncelleme döngüsü için beklemek zorunda kalmadan, bir evented / reaktif programlama üslubuna doğru güncelleme döngü modeli ve daha yürütmek için. Güncelleme döngüsünün kullanımları vardır (geçen oyun süresiyle senkronize edilmesi gereken şeyler için), ancak bileşenlerin kendileri bu desenle kendilerini otomatik olarak güncelleyebildiklerinde bazen onu karıştırmak istemezsiniz.

Gözlenebilir fonksiyonun gerçek uygulaması, yazmak ve anlamak için şaşırtıcı derecede kolaydır (özellikle javascript ve gözlemci modelindeki dizileri nasıl kullanacağınızı biliyorsanız ):

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;
};

JsFiddle'da , bileşenleri gözlemleyerek ve aboneleri kaldırabilmekle devam eden gözlemlenebilir nesnenin bir uygulamasını yaptım . JsFiddle'ı denemek için çekinmeyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.