Yanıtlar:
Temel fark, bir yapıcı işlevinin new
anahtar kelimeyle kullanılmasıdır (bu, JavaScript'in otomatik olarak yeni bir nesne oluşturmasına this
, işlev içinde o nesneye ayarlanmasına ve nesneyi döndürmesine neden olur):
var objFromConstructor = new ConstructorFunction();
Fabrika fonksiyonuna "normal" fonksiyon denir:
var objFromFactory = factoryFunction();
Ancak bir "fabrika" olarak kabul edilebilmesi için, bir nesnenin yeni bir örneğini döndürmesi gerekir: eğer bir boolean veya başka bir şey döndürdüyse buna "fabrika" işlevi demezdiniz. Bu, otomatik olarak olduğu gibi olmaz new
, ancak bazı durumlarda daha fazla esneklik sağlar.
Gerçekten basit bir örnekte, yukarıda atıfta bulunulan işlevler şöyle görünebilir:
function ConstructorFunction() {
this.someProp1 = "1";
this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };
function factoryFunction() {
var obj = {
someProp1 : "1",
someProp2 : "2",
someMethod: function() { /* whatever */ }
};
// other code to manipulate obj in some way here
return obj;
}
Tabii ki fabrika fonksiyonlarını bu basit örnekten çok daha karmaşık hale getirebilirsiniz.
Fabrika fonksiyonlarının bir avantajı, döndürülecek nesnenin bir parametreye bağlı olarak birkaç farklı tipte olabilmesidir.
someMethod
tarafından döndürülen nesneler için geçerli değildir ve burası biraz sisli hale gelir. Fabrika işlevinin içinde, biri yaparsa var obj = { ... , someMethod: function() {}, ... }
, geri gönderilen her nesnenin farklı bir kopyasını someMethod
istemeyeceğimiz farklı bir kopyaya götürür . Kullanarak yani nereye new
ve prototype
fabrika işlevi yardımcı olacağını içeride.
new
yapıcı işleviyle kullanmayı unuttukları hataları bırakmak istemezler ; Birinin nasıl yapıcıları fabrika fonksiyonları örneği ile değiştirmenin gerekli olabileceğini düşündüm ve buradaki örneklerde tutarlılığın gerekli olduğunu düşündüm. Her neyse, cevap yeterince bilgilendirici. Bu sadece yükseltmek istediğim bir noktaydı, herhangi bir şekilde cevabın kalitesini düşürdüğümden değil.
new
Dahili olarak kullanabilir veya Object.create()
belirli bir prototipi olan bir nesne oluşturmak için kullanabilirler .
Çoğu kitap size yapıcıları ve new
this
yeni nesneyi ifade eder
Bazı insanlar var myFoo = new Foo();
okumayı sever .
Gerçekleştirme ayrıntıları, arayan API'ye ( new
gereksinim yoluyla ) sızdırılır , böylece tüm arayanlar yapıcı uygulamasına sıkıca bağlanır. Fabrikanın ek esnekliğine ihtiyacınız varsa, tüm arayanları yeniden düzenlemeniz gerekir (kuşkusuz kural yerine istisnai durum).
Unutmak new
yaygın bir hatadır, kurucunun doğru bir şekilde çağrıldığından emin olmak için bir kazan plakası eklemeyi kuvvetle düşünmelisiniz ( if (!(this instanceof Foo)) { return new Foo() }
). EDIT: ES6 (ES2015) beri new
bir class
yapıcı ile unutamazsınız , ya da yapıcı bir hata atar.
instanceof
Çeki yaparsanız new
, gerekli olup olmadığı konusunda belirsizlik bırakır . Bence öyle olmamalı. new
Gereksinimi etkili bir şekilde kısa devre yaptınız , yani 1 numaralı dezavantajı silebilirsiniz. Ancak daha sonra , ek kazan plakası, büyük harf ve daha az esnek bağlam ile isim dışında bir fabrika fonksiyonuna sahipsinizthis
.
Ama asıl endişem, açık / kapalı prensibini ihlal etmesi. Bir kurucuyu dışa aktarmaya başlıyorsunuz, kullanıcılar kurucuyu kullanmaya başlıyor, daha sonra bunun yerine bir fabrikanın esnekliğine ihtiyacınız olduğunu fark ettiğiniz yolda (örneğin, uygulamayı nesne havuzlarını kullanacak şekilde değiştirmek veya yürütme bağlamlarında örneklemek için veya prototypal OO kullanarak daha fazla kalıtım esnekliğine sahip).
Yine de sıkışıp kaldın. Yapıcıyı çağıran tüm kodu bozmadan değişikliği yapamazsınız new
. Örneğin, performans kazanımları için nesne havuzları kullanmaya geçemezsiniz.
Ayrıca, yapıcıları kullanmak size instanceof
yürütme bağlamlarında çalışmayan ve yapıcı prototipiniz değiştirilirse çalışmayan bir aldatıcılık verir . Ayrıca, kurucunuzdan dönmeye başlar this
ve sonra kurucunuzda fabrika benzeri davranışı etkinleştirmek için yapmanız gereken rasgele bir nesneyi dışa aktarmaya geçerseniz de başarısız olur .
Daha az kod - kaynatma plakası gerekmez.
Herhangi bir rastgele nesneyi döndürebilir ve herhangi bir rastgele prototip kullanabilirsiniz - böylece aynı API'yi uygulayan çeşitli nesne türleri oluşturma konusunda size daha fazla esneklik sağlar. Örneğin, hem HTML5 hem de flash oynatıcı örnekleri oluşturabilen bir medya oynatıcı veya DOM olayları veya web soketi olayları yayabilecek bir olay kütüphanesi. Fabrikalar aynı zamanda yürütme bağlamında nesneleri başlatabilir, nesne havuzlarından yararlanabilir ve daha esnek prototip kalıtım modellerine izin verebilir.
Asla bir fabrikadan bir kurucuya dönüşmenize gerek kalmaz, bu yüzden yeniden düzenleme asla sorun olmaz.
Kullanmayla ilgili bir belirsizlik yok new
. Yapma. ( this
Kötü davranacaktır, bir sonraki noktaya bakınız).
this
normalde olduğu gibi davranır - böylece üst nesneye erişmek için kullanabilirsiniz (örneğin, içeride player.create()
, tıpkı diğer herhangi bir yöntem çağrısında olduğu gibi this
anlamına gelir) ve beklendiği gibi yeniden player
atayabilirsiniz . Prototipleri üst nesnede depolarsanız, işlevselliği dinamik olarak değiştirmenin ve nesne somutlaştırmanız için çok esnek bir polimorfizme olanak sağlamanın harika bir yolu olabilir.call
apply
this
Büyük harf kullanımı olup olmamasına dair belirsizlik yok. Yapma. Tüy bırakmayan araçlar şikayet edecek ve sonra kullanmaya çalışacaksınız new
ve daha sonra yukarıda açıklanan avantajı geri alacaksınız.
Bazı insanlar okumayı var myFoo = foo();
veya var myFoo = foo.create();
okumayı sever .
new
beklendiği gibi davranmaz (yukarıya bakınız). Çözüm: kullanma.
this
Yeni bir nesne ifade etmez (yapıcı nokta gösterimde veya köşeli ayraç gösterimde, örneğin foo.bar () çağrıldığında, bunun yerine, - this
atıfta foo
yararlarını görmek - sadece her JavaScript yöntemi gibi -).
new
duymanın açık / kapalı prensibini ihlal etmesidir. Bu yorumların izin verdiğinden çok daha büyük bir tartışma için medium.com/javascript-scene/… adresine bakın .
new
anahtar kelime olmadan bunu yapabildiğinden , new
anahtar kelimenin aslında ek okunabilirlik sağladığına inanmıyorum . IMO, arayanların daha fazla yazmasını sağlamak için çemberlerden atlamak aptalca görünüyor.
Bir kurucu, çağırdığınız sınıfın bir örneğini döndürür. Fabrika işlevi her şeyi döndürebilir. Rasgele değerler döndürmeniz gerektiğinde veya bir sınıfın büyük bir kurulum işlemi olduğunda fabrika işlevini kullanırsınız.
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");
new
prototiplenmiş bir nesne oluşturur ve yaratılan nesne ile değeri olarak User.prototype
çağırır .User
this
new
işlenen için bir argüman ifadesini isteğe bağlı olarak ele alır:
let user = new User;
hiçbir argüman olmadan new
çağrı neden olur User
.
new
yapıcı bunun yerine döndürülen bir nesne değeri döndürmediği sürece oluşturduğu nesneyi döndürür . Bu, çoğunlukla göz ardı edilebilecek bir kenar durumudur.
Yapıcı işlevleri tarafından oluşturulan nesneler, özellikleri yapıcı özelliğinden devralır ve yapıcı işlevindeki işleci prototype
kullanarak true değerini döndürür instanceOf
.
Yapıcıyı prototype
zaten kullandıktan sonra yapıcı özelliğinin değerini dinamik olarak değiştirirseniz, yukarıdaki davranışlar başarısız olabilir . Bunu yapmak nadirdir ve yapıcı class
anahtar kelime kullanılarak oluşturulmuşsa değiştirilemez .
Yapıcı işlevleri extends
anahtar sözcük kullanılarak genişletilebilir .
Yapıcı işlevleri null
hata değeri olarak geri dönemez . Nesne veri türü olmadığından tarafından yoksayılır new
.
function User(name, age) {
return {
name,
age,
}
};
let user = User("Tom", 23);
Burada fabrika fonksiyonu olmadan çağrılır new
. İşlev, bağımsız değişkenleri ve döndürdüğü nesne türünde doğrudan veya dolaylı kullanımdan tamamen sorumludur. Bu örnekte, argümanlardan ayarlanmış bazı özelliklere sahip basit bir [Nesne nesnesi] döndürür.
Kolayca arayandan nesne oluşturma uygulama karmaşıklığını gizler. Bu özellikle bir tarayıcıdaki yerel kod işlevleri için kullanışlıdır.
Fabrika işlevinin her zaman aynı türdeki nesneleri döndürmesi gerekmez ve hatta null
bir hata göstergesi olarak geri dönebilir .
Basit durumlarda, fabrika fonksiyonları yapı ve anlam bakımından basit olabilir.
İade nesneleri genellikle fabrika işlevin devralan yok prototype
mülkiyet ve karşılığında false
gelen instanceOf factoryFunction
.
Fabrika işlevi, extends
anahtar sözcük kullanılarak güvenli bir şekilde genişletilemez, çünkü genişletilmiş nesneler fabrika işlevi tarafından kullanılan yapıcıdan prototype
ziyade fabrika işlevleri özelliğinden miras alınır prototype
.
Fabrikalar "her zaman" daha iyidir. Nesneye yönelik dilleri kullanırken
Uygulamalar (yeni ile oluşturulan gerçek nesneler) fabrika kullanıcısına / tüketicisine maruz kalmaz. Bu, fabrika geliştiricisinin sözleşmeyi ihlal etmediği sürece yeni uygulamaları genişletebileceği ve oluşturabileceği anlamına gelir ... ve fabrika tüketicisinin kodlarını değiştirmek zorunda kalmadan yeni API'den faydalanmasını sağlar ... eğer yeni kullandılar ve "yeni" bir uygulama gelirse, "yeni" uygulamayı kullanmak için "yeni" kullanan her satırı değiştirmek zorunda kalırlar ... fabrika ile kodları değişmez ...
Fabrikalar - her şeyden daha iyi - bahar çerçevesi tamamen bu fikir üzerine inşa edilmiştir.
Fabrikalar bir soyutlama katmanıdır ve tüm soyutlamalar gibi karmaşıklığa da sahiptirler. Fabrika tabanlı bir API ile karşılaştığınızda, belirli bir API için fabrikanın ne olduğunu bulmak API tüketicisi için zor olabilir. Yapıcılar ile keşfedilebilirlik önemsizdir.
Ctorlar ve fabrikalar arasında karar verirken, karmaşıklığın fayda tarafından haklı olup olmadığına karar vermeniz gerekir.
Javascript kurucularının bundan başka bir şey döndürerek veya tanımsız olarak rastgele fabrikalar olabileceğini belirtmek gerekir. Böylece js'de her iki dünyanın en iyisini elde edebilirsiniz - keşfedilebilir API ve nesne havuzlama / önbellekleme.
new
, Değişme davranışı this
, Dönüş değerini değiştirme, Bir prototip ref bağlanması, Etkinleştirme instanceof
(bu amaç için kullanılır ve kullanılmamalıdır). Görünüşte, bunların hepsi "özellikler" dir. Uygulamada, kod kalitenize zarar verirler.