Uyarı: Bu uzun bir gönderi.
Basit tutalım. JavaScript'te her yapıcıyı çağırdığımda yeni operatörün önekini kullanmaktan kaçınmak istiyorum. Çünkü unutmaya eğilimliyim ve kodum kötü bir şekilde vidalanıyor.
Bunun basit yolu şudur ...
function Make(x) {
if ( !(this instanceof arguments.callee) )
return new arguments.callee(x);
// do your stuff...
}
Ancak, değişken no'yu kabul etmek için buna ihtiyacım var. gibi argümanların ...
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
İlk acil çözüm böyle 'uygula' yöntemi gibi görünüyor ...
function Make() {
if ( !(this instanceof arguments.callee) )
return new arguments.callee.apply(null, arguments);
// do your stuff
}
Ancak bu YANLIŞ - yeni nesne yapıcıya applydeğil , yönteme geçirilir arguments.callee.
Şimdi üç çözüm buldum. Basit sorum şu: hangisi daha iyi görünüyor. Veya daha iyi bir yönteminiz varsa, söyleyin.
İlk olarakeval() , yapıcıyı çağıran JavaScript kodunu dinamik olarak oluşturmak için kullanın .
function Make(/* ... */) {
if ( !(this instanceof arguments.callee) ) {
// collect all the arguments
var arr = [];
for ( var i = 0; arguments[i]; i++ )
arr.push( 'arguments[' + i + ']' );
// create code
var code = 'new arguments.callee(' + arr.join(',') + ');';
// call it
return eval( code );
}
// do your stuff with variable arguments...
}
İkincisi - Her nesnenin, __proto__prototip nesnesine bir 'gizli' bağlantı olan özelliği vardır. Neyse ki bu özellik yazılabilir.
function Make(/* ... */) {
var obj = {};
// do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// now do the __proto__ magic
// by 'mutating' obj to make it a different object
obj.__proto__ = arguments.callee.prototype;
// must return obj
return obj;
}
Üçüncü - Bu ikinci çözüme benzer bir şeydir.
function Make(/* ... */) {
// we'll set '_construct' outside
var obj = new arguments.callee._construct();
// now do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// you have to return obj
return obj;
}
// now first set the _construct property to an empty function
Make._construct = function() {};
// and then mutate the prototype of _construct
Make._construct.prototype = Make.prototype;
evalçözüm beceriksiz görünüyor ve "kötü eval" tüm sorunları ile geliyor.__proto__çözüm standart değildir ve "mIsERY'nin Büyük Tarayıcısı" onurlandırmaz.Üçüncü çözüm aşırı karmaşık görünüyor.
Ancak yukarıdaki üç çözümün hepsiyle, bunun gibi bir şey yapabiliriz, aksi takdirde yapamayız ...
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
m1 instanceof Make; // true
m2 instanceof Make; // true
m3 instanceof Make; // true
Make.prototype.fire = function() {
// ...
};
m1.fire();
m2.fire();
m3.fire();
Dolayısıyla yukarıdaki çözümler bize değişken no'yu kabul eden "gerçek" kurucuları vermektedir. ve gerektirmez new. Bu konuda ne düşünüyorsun.
-- GÜNCELLEME --
Bazıları "sadece bir hata at" dedi. Benim cevabım: 10'dan fazla kurucu ile ağır bir uygulama yapıyoruz ve her kurucu konsolda hata mesajları atmadan bu hatayı "akıllıca" ele alsaydı çok daha zahmetli olacağını düşünüyorum.
Make()Olmadan yaparsanız sizi uyaracaktır , newçünkü Make büyük harfle yazılmıştır ve bu nedenle bir kurucu olduğunu varsayar
new? Çünkü ikinciyse, muhtemelen yanlış sitede soruyorsunuzdur. Eski ise, yeni ve hataların bu kadar hızlı algılanmasıyla ilgili önerileri reddetmek istemeyebilirsiniz ... Uygulamanız gerçekten "ağır" ise, istediğiniz son şey yavaşlatmak için aşırı işlenmiş bir inşaat mekanizmasıdır. new, aldığı tüm flack için oldukça hızlı.