JS nesnelerini bu şekilde tanımlamanın herhangi bir amacı var mı?


87

Bazı eski kodları koruyorum ve nesneleri tanımlamak için aşağıdaki modelin kullanıldığını fark ettim:

var MyObject = {};

(function (root) {

    root.myFunction = function (foo) {
        //do something
    };

})(MyObject);

Bunun bir amacı var mı? Sadece aşağıdakileri yapmaya eşdeğer mi?

var MyObject = {

    myFunction : function (foo) {
        //do something
    };

};

Tüm kod tabanını kendi zevkime göre yeniden düzenlemek için kutsal bir arayışa girmek üzere değilim, ancak nesneleri tanımlamanın bu dolambaçlı yolunun arkasındaki sebebi gerçekten anlamak istiyorum.

Teşekkürler!


1
Tam örneğinizde bir fark yok. Eğer onu genişletirseniz, bir fark olabilir ancak o zaman oyuna giren farklı yaklaşımlar da olacaktır.
Travis J

Hiçbir fark yaratmaz, nesneler tabiri caizse bir referansın kopyası olarak aktarılır, bu yüzden IIFE içinde myFunction tanımlanırken bile, yine de onun dışında erişilebilir.
adeneo

1
@adeneo Bu örnek için myFunctiondeğil, dışarıdan erişilemeyen kendi dışında tanımlanan bazı değişkenleri kullanabilir. Cevabımı görün
Juan Mendes

2
olası bir kopyası Bu JavaScript kalıbı nedir ve neden kullanılır? (kapatmam gerekip gerekmediğinden emin değilim). Ayrıca JavaScript Namespace Declaration veya buna bakın .
Bergi

Yanıtlar:


116

Buna http://toddmotto.com/mastering-the-module-pattern/ modül kalıbı denir

Bunun ana nedeni, gerçekten özel yöntemler ve değişkenler oluşturmanızdır. Sizin durumunuzda, herhangi bir uygulama detayını saklamadığı için anlamlı değil.

İşte modül modelini kullanmanın anlamlı olduğu bir örnek.

var MyNameSpace = {};

(function(ns){
    // The value variable is hidden from the outside world
    var value = 0;

    // So is this function
    function adder(num) {
       return num + 1;
    }

    ns.getNext = function () {
       return value = adder(value);
    }
})(MyNameSpace);

var id = MyNameSpace.getNext(); // 1
var otherId = MyNameSpace.getNext(); // 2
var otherId = MyNameSpace.getNext(); // 3

Hâlbuki sadece düz bir nesne kullanırsanız adderve valuehalka açılırsanız

var MyNameSpace = {
    value: 0,
    adder: function(num) {
       return num + 1;
    },
    getNext: function() {
       return this.value = this.adder(this.value);
    }
}

Ve gibi şeyler yaparak onu kırabilirsin

MyNameSpace.getNext(); // 1
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 1 again
delete MyNameSpace.adder;
MyNameSpace.getNext(); // error undefined is not a function

Ancak modül versiyonuyla

MyNameSpace.getNext(); // 1
 // Is not affecting the internal value, it's creating a new property
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 2, yessss
// Is not deleting anything
delete MyNameSpace.adder;
MyNameSpace.getNext(); // no problemo, outputs 3

2
Bu, iki alternatif arasındaki farkın ne olduğu sorusuna gerçekten cevap vermiyor mu?

20
@torazaburo OP'nin örneği iyi bir örnek değildi, modül modelinin ne zaman kullanılacağını gösteren gerçek bir örnek verdim.
Juan Mendes

Bu ns.getNext: function () {derlenmeyecek.
2014

Nasıl düzelteceğime emin olsaydım yapardım. Önlenecek bir yapı olduğunu düşündüm delete MyNameSpace.getNext.
2014

2
@punund JS'nin derleyicisi yok, yorumlayıcı var:)
frogatto

22

Amaç, diğer komut dosyalarının üzerinde kod yürütmesini önlemeye yardımcı olmak için kapatma içindeki işlevlerin erişilebilirliğini sınırlamaktır . Bunu bir kapanışın etrafına sararak , kapanış içindeki tüm kod için yürütme kapsamını yeniden tanımlıyorsunuz ve etkili bir şekilde özel bir kapsam oluşturuyorsunuz. Daha fazla bilgi için bu makaleye bakın:

http://lupomontero.com/using-javascript-closures-to-create-private-scopes/

Makaleden:

JavaScript'teki en iyi bilinen sorunlardan biri, küresel kapsama olan bağımlılığıdır; bu, temelde, bir işlevin dışında bildirdiğiniz tüm değişkenlerin aynı ad alanında yaşadığı anlamına gelir: uğursuz pencere nesnesi. Web sayfalarının doğası gereği, farklı kaynaklardan gelen birçok komut dosyası, ortak bir genel kapsamı paylaşan aynı sayfada çalışabilir (ve çalışacaktır) ve bu, ad çakışmalarına (aynı ada sahip değişkenler) yol açabileceği için gerçekten kötü bir şey olabilir. üzerine yazılıyor) ve güvenlik sorunları. Sorunu en aza indirmek için, değişkenlerimizin sayfadaki diğer komut dosyaları tarafından görünmez olduğundan emin olabileceğimiz özel kapsamlar oluşturmak için JavaScript'in güçlü kapanışlarını kullanabiliriz.



Kod:

var MyObject = {};

(function (root) {
    function myPrivateFunction() {
       return "I can only be called from within the closure";
    }

    root.myFunction = function (foo) {
        //do something
    };    

    myPrivateFunction(); // returns "I can only be called from within the closure"

})(MyObject);


myPrivateFunction(); // throws error - undefined is not a function

1
myFunctionikinci versiyonda genel kapsamda değildir. Amaç aslında dahili yardımcı fonksiyonların tanımlanabileceği bir kapsam sağlamaktır.
Barmar

myFunctionglobal nesne içinde tanımlandığı için global kapsamdadır myObject. İkinci versiyonda, uygulamadaki diğer herhangi bir kod çalıştırılabilir myFunction. İlk versiyonda sadece kapağın içindeki kodun erişimi varmyFunction
Jonathan Crowe

Hayır, myFunctionyalnızca MyObject.myFunction()ilk sürümle aynı şekilde çalıştırılabilir .
Barmar

@JonathanCrowe OP'nin örneği iyi bir örnek değil, modülün içindeki her şeyi açığa çıkarıyor, yani evet, dışarıdan erişilebilir hale geliyor. Yararlı bir modül vaka için Cevabımı bakın
Juan Mendes

@JuanMendes iyi bir nokta, OP'nin örneği modül modelinin harika bir kullanımı değil
Jonathan Crowe

6

avantajları:

  1. değişkenleri özel kapsamda tutar.

  2. mevcut nesnenin işlevselliğini artırabilirsiniz.

  3. performans artar.

Bence yukarıdaki üç basit nokta bu kurallara uymak için yeterli. Ve onu basit tutmak için, içsel işlevleri yazmaktan başka bir şey değildir.


6

Gösterdiğiniz özel durumda, işlevsellik veya görünürlük açısından anlamlı bir fark yoktur.

Orijinal kodlayıcının bu yaklaşımı, aşağıdakiler gibi şeylerin tanımında kullanılabilecek özel değişkenleri tanımlamasına izin veren bir tür şablon olarak benimsemiş olması muhtemeldir myFunction:

var MyObject = {};
(function(root) {
    var seconds_per_day = 24 * 60 * 60;   // <-- private variable
    root.myFunction = function(foo) {
        return seconds_per_day;
    };
})(MyObject);

Bu seconds_per_day, işlev her çağrıldığında hesaplamayı önler ve aynı zamanda küresel kapsamı kirletmesini önler .

Ancak, esasen bundan farklı hiçbir şey yoktur

var MyObject = function() {
    var seconds_per_day = 24 * 60 * 60;
    return {
        myFunction: function(foo) {
            return seconds_per_day;
        }
    };
}();

Orijinal kodlayıcı root.myFunction = function, nesnenin nesne / özellik sözdizimi yerine bildirim temelli sözdizimini kullanarak nesneye işlevler eklemeyi tercih etmiş olabilir myFunction: function. Ancak bu fark esas olarak bir tercih meselesidir.

Bununla birlikte, orijinal kodlayıcı tarafından alınan yapı, özelliklerin / yöntemlerin kodun başka bir yerine kolayca eklenebilmesi avantajına sahiptir:

var MyObject = {};
(function(root) {
    var seconds_per_day = 24 * 60 * 60;
    root.myFunction = function(foo) {
        return seconds_per_day;
    };
})(MyObject);

(function(root) {
    var another_private_variable = Math.pi;
    root.myFunction2 = function(bar) { };
})(MyObject);

Sonuç olarak, ihtiyacınız yoksa bu yaklaşımı benimsemenize gerek yoktur, ancak mükemmel bir şekilde çalıştığı ve aslında bazı avantajları olduğu için değiştirmeye de gerek yoktur.


6
  1. İlk desen, bir nesneyi alan ve bazı değişikliklerle o nesneyi döndüren bir modül olarak kullanılabilir. Diğer bir deyişle, bu tür modülleri aşağıdaki gibi tanımlayabilirsiniz.

    var module = function (root) {
        root.myFunction = function (foo) {
            //do something
        };
    }
    

    Ve şu şekilde kullanın:

    var obj = {};
    module(obj);
    

    Bu nedenle, bu modülün daha sonraki kullanımlar için yeniden kullanılabilir olması bir avantaj olabilir.


  1. İlk desende, özel özellikler ve yöntemler gibi özel öğelerinizi depolamak için özel bir kapsam tanımlayabilirsiniz . Örneğin, şu pasajı düşünün:

    (function (root) {
    
        // A private property
        var factor = 3;
    
        root.multiply = function (foo) {
            return foo * factor;
        };
    })(MyObject);
    

  1. Bu desen, diziler, nesne değişmezleri, işlevler gibi tüm nesne türlerine bir yöntem veya özellik eklemek için kullanılabilir.

    function sum(a, b) {
        return a + b;
    }
    
    (function (root) {
        // A private property
        var factor = 3;
        root.multiply = function (foo) {
            return foo * factor;
        };
    })(sum);
    
    console.log(sum(1, 2)); // 3
    console.log(sum.multiply(4)); // 12
    

Bence asıl avantaj ikincisi olabilir (özel bir kapsam oluşturmak)


5

Bu kalıp, genel kapsamda görünmeyen yardımcı işlevleri tanımlayabileceğiniz bir kapsam sağlar:

(function (root) {

    function doFoo() { ... };

    root.myFunction = function (foo) {
        //do something
        doFoo();
        //do something else
    };

})(MyObject);

doFoo anonim işlev için yereldir, dışarıdan referans alınamaz.

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.