Prototip ile Kendiliğinden Çalışan Anonim İşlev


26

Javascript'te, javascript'te sınıfları / ad alanlarını oluşturmak ve yönetmek için açıkça öne çıkan birkaç teknik vardır.

Bir durumu diğerine karşı hangi durumlarda kullanmak istediğini merak ediyorum. Bir tane seçip ilerlemeye devam etmek istiyorum.

Birden fazla ekip tarafından tutulan ve paylaşılan işletme kodunu yazıyorum ve korunabilir javascript yazarken en iyi uygulamanın ne olduğunu bilmek istiyorum?

Kendiliğinden Çalışan Anonim İşlevleri tercih etme eğilimindeyim, ancak topluluk oylarının bu tekniklerde ne olduğunu merak ediyorum.

Prototip:

function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

Kendiliğinden Kapanan Anonim İşlev:

//Self-Executing Anonymous Function 
(function( skillet, $, undefined ) {
    //Private Property
    var isHot = true;

    //Public Property
    skillet.ingredient = "Bacon Strips";

    //Public Method
    skillet.fry = function() {
        var oliveOil;

        addItem( "\t\n Butter \n\t" );
        addItem( oliveOil );
        console.log( "Frying " + skillet.ingredient );
    };

    //Private Method
    function addItem( item ) {
        if ( item !== undefined ) {
            console.log( "Adding " + $.trim(item) );
        }
    }     
}( window.skillet = window.skillet || {}, jQuery ));   
//Public Properties      
console.log( skillet.ingredient ); //Bacon Strips  

//Public Methods 
skillet.fry(); //Adding Butter & Fraying Bacon Strips 

//Adding a Public Property 
skillet.quantity = "12"; console.log( skillet.quantity ); //12   

//Adding New Functionality to the Skillet 
(function( skillet, $, undefined ) {
    //Private Property
    var amountOfGrease = "1 Cup";

    //Public Method
    skillet.toString = function() {
        console.log( skillet.quantity + " " + 
                     skillet.ingredient + " & " + 
                     amountOfGrease + " of Grease" );
        console.log( isHot ? "Hot" : "Cold" );
     };     

}( window.skillet = window.skillet || {}, jQuery ));
//end of skillet definition


try {
    //12 Bacon Strips & 1 Cup of Grease
    skillet.toString(); //Throws Exception 
} catch( e ) {
    console.log( e.message ); //isHot is not defined
}

Kendiliğinden Çalışan Anonim İşlev'in jQuery ekibi tarafından kullanılan kalıptan bahsetmem gerektiğini düşünüyorum.

Güncelle Bu soruyu sorduğumda anlamaya çalıştığım şeyin önemini gerçekten görmedim. Eldeki asıl mesele nesnelerinizin örneklerini oluşturmak için yeniyi kullanıp kullanmamak veya newanahtar kelime yapıcıları / kullanımı gerektirmeyen kalıpları kullanmaktır .

Kendi cevabımı ekledim, çünkü bence newanahtar kelimeyi kullanmayan kalıpları kullanmalıyız .

Daha fazla bilgi için lütfen cevabımı görün.


1
Tarif ettiğiniz iki tekniğin kısa örneklerini verebilir misiniz?
Hey,

Basit örneklemim yüzünden prototipi küçümseme.
Robotsushi

1
kendisini yürütmüyor = /
Hey,

2
ifadeyi kapatmak veya aramak için parantez göremiyorum ...
Hey

1
(+1) Ad alanları birçok geliştirici için göz ardı edildi.
umlcat, 19

Yanıtlar:


22

Kendiliğinden çalışan anonim işlevler, harici olaylara (örn. Window.onload) takılmadan komut dosyası yürütülmesini otomatikleştirmek için kullanılır.

Bu örnekte, temel amacı küresel ortama bir ad alanı tanıtmak ve "dışa aktarılmayan" ya da ad alanına eklenmemiş herhangi bir iç özellik için enkapsülasyon sağlamak olan klasik Modül modelini oluşturmak için kullanılır .

Bir nesnenin prototipini değiştirmek, diğer yandan, miras oluşturmak (veya yerlileri uzatmak) için kullanılır. Bu desen, ortak yöntem veya özelliklere sahip 1: n nesneler üretmek için kullanılır.

Sen bir desen tercih edilmemelidir tercihi yaptıkları beri, diğerine farklı görevler. Ad alanı açısından, Kendi Kendine Yürütme İşlevi uygun bir seçimdir.


7
"Kendiliğinden çalışan anonim işlevleri" genellikle hemen çağrılan işlev ifadeleri (IIFE) olarak bilinir .
voithos

Onlardan kaçınıyorum ve dürüst olmak gerekirse, IIFE'ler ile aşkı alamıyorum. Eclipse’de kod taslağını ayıklamak ve kırmak için dağınıktırlar. Bir ad alanına ihtiyacınız varsa, onu bir nesneye yapıştırın, onu çalıştırmanız gerekirse, sadece onu çağırın ve kapsülleme bana gerçekten bir şey kazandırmaz.
Daniel Sokolowski

4

İşte kullanmaya başladığım model şu: (Düne kadar varyasyonları kullanıyordum):

function MyClass() {
    // attributes
    var privateVar = null;

    // function implementations
    function myPublicFunction() {
    }

    function myPrivateFunction() {
    }

    // public declarations
    this.myPublicFunction = myPublicFunction;
}

MyClass.prototype = new ParentClass(); // if required

Bununla ilgili birkaç düşünce:

  1. (anonymous)Hata ayıklayıcı yığın izlerinizde, her şeyin adı olduğu gibi hiçbir iz yakalamamalısınız (adsız işlev yok).
  2. Bu şimdiye kadar gördüğüm en temiz kalıp
  3. Açıklamalı API’nizi, uygulamalarını bildirime eşlik etmeden kolayca gruplandırabilirsiniz (yani, birileri genel sınıf arabiriminizi kaydırma yapmadan kolayca kaldırabilir)

prototypeArtık kullanabileceğim tek zaman, mirası tanımlamak.


5
Bununla ilgili birkaç sorun var. Her "yöntem" için yapıcının her çağrılışında yeni bir işlev nesnesi oluşturulur. Ayrıca, kalıtım için prototip nesnesinin bir kopyasını almak için bir yapıcıyı çağırmak üzerine kaşlarını çattı. Object.create (ParentClass.prototype) veya Object.create gibi bir şim kullanınfunction clone(obj){return this typeof 'clone' ? this : new clone(clone.prototype=obj)}
Hey

@GGG: Evet, ilk noktan konusunda haklısın. Bir uygulamanın her bir özel kullanım durumunun düşünülmesi gerektiğini (ve görevimde belirtmeliydim) derdim. Önerdiğin prototypeyöntemle ilgili sorunum (aşina olduğum bir yöntem olmadığı sürece, ki bu olabilir), nitelikleri kapama yeteneğini kaybettiğin, her şeyin halka açık olduğu anlamına gelen (dünyanın sonu olmayan). , sadece kişisel bir tercih).
Demian Brecht

Ayrıca, jsperf'te ( jsperf.com/object-create-vs-constructor-vs-object-literal/12 ) yapılan aşağıdaki çalışmaları inceledikten sonra , hemen hemen her gün ek kopyaların bellek maliyeti üzerindeki performans artışını alırdım (yine, belirli kullanım durumuna çok öznel).
Demian Brecht

Şimdi, hepsini söyledikten sonra, sadece ECMA-262'ye giriyorum, bu yüzden göremediğim bir sürü şey olabilir. Ayrıca, Crockford'un sözünü müjde olarak kabul etmiyorum .. Evet, o bir Alanında uzman kişilerden biri (elbette en önde gelenlerinden biri), ancak onu her zaman% 100 doğru yapmaz. Zorlayıcı argümanlarla çelişkili görüşleri olan başka uzmanlar da var (onlardan biri olmamalı).
Demian Brecht


3

Kullandığım prototipler onlar daha temizdir ve standart kalıtım çünkü. Kendi kendine arama işlevleri, tarayıcı geliştirme veya kodun nerede yürütüldüğünü bilmediğiniz bir durum için mükemmeldir, ancak aksi takdirde sadece gürültüden oluşur.

Örnek:

var me;

function MyObject () {
    this.name = "Something";
}

MyObject.prototype.speak = function speak () {
    return "Hello, my name is " + this.name;
};

me = new MyObject();
me.name = "Joshua";
alert(me.speak());

1
Kendiliğinden çalışan anonim işlevler, bir sınıfa erişebileceğiniz özel işlevlere sahip olmanız için çok kullanışlıdır.
Zee

1

Kendi kendine çalışan fonksiyonu ile giderdim, ancak küçük bir farkla:

MyClass = (function() {
     var methodOne = function () {};
     var methodTwo = function () {};
     var privateProperty = "private";
     var publicProperty = "public";

     return function MyClass() {
         this.methodOne = methodOne;
         this.methodTwo = methodTwo;
         this.publicProperty = publicProperty;
     };
})();

Bu yaklaşımı daha temiz bulursam, döndürülen global değişkeni herhangi bir girdi parametresinden (örneğin, jQuery gibi) ayırdığımdan (bunu yazdığınız şekilde, boşa döndürme ve biraz kapalı bulduğum C # 'ta bir ref parametresi kullanmaya eşdeğerdir) veya bir göstericiye bir göstericiye geçme ve C ++ 'a yeniden atama). O zaman sınıfa ek yöntemler ya da özellikler ekleyeceksem prototip kalıtım kullanırdım (jQuery'nin $ .extend yöntemiyle örnek, ama kendi extend'ini () eklemek yeterince kolaydı:

var additionalClassMethods = (function () {
    var additionalMethod = function () { alert('Test Method'); };
    return { additionalMethod: additionalMethod };
})();

$.extend(MyClass.prototype, additionalClassMethods);

var m = new MyClass();
m.additionalMethod(); // Pops out "Test Method"

Bu şekilde, eklenen yöntemler ile orijinal olanlar arasında açık bir fark vardır.


1
NFE'leri bu şekilde kullanmayı düşünen tek kişi benim için kötü bir fikir mi?
Hey

1

Canlı Örnek

(function _anonymouswrapper(undefined) {

    var Skillet = {
        constructor: function (options) {
            options && extend(this, options);
            return this; 
        },
        ingredient: "Bacon Strips",
        _isHot: true,
        fry: function fry(oliveOil) {
            this._addItem("\t\n Butter \n\t");
            this._addItem(oliveOil);
            this._addItem(this.ingredient);
            console.log("Frying " + this.ingredient);
        },
        _addItem: function addItem(item) {
            console.log("Adding " + item.toString().trim());
        }
    };

    var skillet = Object.create(Skillet).constructor();

    console.log(skillet.ingredient);
    skillet.fry("olive oil");

    var PrintableSkillet = extend(Object.create(Skillet), {
        constructor: function constructor(options) {
            options && extend(this, options);
            return this;
        },
        _amountOfGrease: "1 Cup",
        quantity: 12,
        toString: function toString() {
            console.log(this.quantity + " " +
                        this.ingredient + " & " +
                        this._amountOfGrease + " of Grease");
            console.log(this._isHot ? "Hot" : "Cold");
        }
    });

    var skillet = Object.create(PrintableSkillet).constructor();

    skillet.toString();

    function extend(target, source) {
        Object.getOwnPropertyNames(source).forEach(function (name) {
            var pd = Object.getOwnPropertyDescriptor(source, name);
            Object.defineProperty(target, name, pd);
        });
        return target;
    }
}());

Kodunuzun etrafında "modül kapsamını" taklit etmek için bir IIFE kullanabilirsiniz. Sonra normalde yaptığınız gibi sadece nesneleri kullanabilirsiniz.

Özel hanehalkını büyük bir hafıza cezasına sahip olduğu için kapama kullanarak "taklit etmeyin".

Eğer bir kurumsal başvuru yazıyorsanız ve hafıza kullanımınızı 1GB'ın altında tutmak istiyorsanız, saklamak için gereksiz yere kapak kullanmaktan kaçının.


Kodda bir kaç yazım hatası var. Otomatik olarak aşırı bellek kullanımına neden olan kapatma iddiası konusunda da olumlu değilim, bence bunları ne kadar yoğun kullandığınıza ve kapsam belirleme sorunlarıyla ne kadar iyi çalıştığınıza (dışardan bir şeyi dışardan gelen şeylerle karıştırmak) genellikle kötü, örneğin (genel konsolu kullanımınız buna iyi bir örnektir, eğer konsolda bir değişken olarak geçtiyseniz, yukarıdaki kod daha verimli olacaktır).
Ed James

@EdWoodcock Kodun hatalı olduğunu düşündüm, yeniden kırıldı ve düzelttim.
Raynos,

@EdWoodcock yerel consoleve global arasındaki verimlilik farkı consolebir mikro optimizasyondur. console
Yapmaya

@EdWoodcock kapaklar, çoğaltan nesneleriniz içindeyse yavaştır. Yavaş olan, ihtiyaç duyulmadığında işlevlerin içinde işlevler oluşturmaktır. Kapanışlar aynı zamanda devleti doğrudan nesnelerde saklamaya kıyasla devleti depolamak için ek
yüklere sahip değildir

Evet, sadece şunu belirtmek istedim, çünkü cevabınız şeyleri ele almak için makul bir yoldur (kullanmayı tercih ettiğim yol olmasa da). (Bir düzenleme yapmış olurdum ama hala bu belirli SE sitesindeki görgü kuralları hakkında emin değilim).
Ed James

0

Güncelleme Artık javascript hakkında daha iyi bir anlayışa sahibim ve soruyu doğru bir şekilde çözebileceğimi hissediyorum. Bence kötü ifade edilmiş, ancak ele alınması gereken çok önemli bir javascript konusu.

Kendiliğinden Yürütülen Anonim İşlev kalıbı, işlevlerin dışında kullanılmasını engellerseniz, yeni anahtar kelimenin kullanılmasını gerektiren bir model değildir. Yeni kullanmanın eski bir teknik olduğu fikrine katılıyorum ve bunun yerine yeni kullanımdan kaçınan kalıpları kullanmaya çalışmalıyız.

Kendiliğinden Çalışan Anonim İşlev bu ölçütleri karşılar.

Bu sorunun cevabı özneldir, çünkü javascript'te çok fazla kodlama stili vardır. Ancak araştırma ve deneyimlerime dayanarak, API'lerinizi tanımlamak ve mümkün olduğunda yenilerini kullanmaktan kaçınmak için Kendiliğinden Çalışan Anonim İşlevini kullanmayı seçmenizi tavsiye ederim.


1
Yeni anahtar kelimenin nesi kötü? Merak ediyorum.
Ally

0

İşte bu konuda giderdim nasıl IIFE SelfExecutingFunctionuzatmak Myclassile Myclass.anotherFunction();

MyClass = (function() {
     var methodOne = function () {};
     var methodTwo = function () {};
     var privateProperty = "private";
     var publicProperty = "public";

    //Returning the anonymous object {} all the methods and properties are reflected in Myclass constructor that you want public those no included became hidden through closure; 
     return {
         methodOne = methodOne;
         methodTwo = methodTwo;
         publicProperty = publicProperty;
     };
})();

@@@@@@@@@@@@@@@@@@@@@@@@
//then define another IIFE SEF to add var function=anothermethod(){};
(function(obj){
return obj.anotherfunction=function(){console.log("Added to Myclass.anotherfunction");};
})(Myclass);

//the last bit : (function(obj){})(Myclass); obj === Myclass obj is an alias to pass the Myclass to IIFE

var myclass = new Myclass();
myclass.anotherfunction(); //"Added to Myclass.anotherfunction"

1
Programcılar turda kavramsal sorular cevapları anlatması bekleniyor. Açıklama yerine kod dökümlerini atmak, kodu IDE'den beyaz tahtaya kopyalamak gibidir: tanıdık gelebilir ve hatta bazen anlaşılabilir görünebilir, ancak garip ... sadece garip geliyor. Beyaz Tahta derleyici yok
gnat
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.