JavaScript'te bir ad alanını nasıl bildirebilirim?


990

JavaScript'te, nesnelerimin ve işlevlerimin aynı adlı diğer nesneler ve işlevler tarafından üzerine yazılmaması için nasıl ad alanı oluşturabilirim? Aşağıdakileri kullandım:

if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}

Bunu yapmanın daha zarif veya özlü bir yolu var mı?


20
İsim alanının alınıp alınmadığını kontrol etmek için nereye gittiğinizi görebilirim, ancak bu başarısız olursa nesne yaratılamayacağından, isim alanının alınması durumunda daha iyi bir yaklaşımın uyarılması olduğunu düşünüyorum. Açıkçası bu sadece birçok JS durumunda olmamalı ve geliştirme aşamasında hızlıca yakalanmalıdır.
annakata

18
Üst düzey bir "ad alanı" (pencere özelliği) alın. Sahip olun. Çatışmalar testte erkenden tespit edilmelidir. Tüm bu "ne olursa olsun" kontrolleri eklemek zahmet etmeyin. Yinelenen "ad alanları" için ölümcül bir konudur ve bu şekilde ele alınmalıdır . Özel bir "ad alanı" yerleşimine izin vermek için jQuery gibi bir yaklaşımı takip edebilirsiniz; ancak bu hala tasarım zamanı meselesidir.

Lütfen kabul ettiğiniz cevabı çok daha zarif ve güncel bir çözüm olan stackoverflow.com/questions/881515/… olarak değiştirin .
hlfcoding

@pst YUI ne yapar? Tam olarak ad alanlarına eklemeler için bunu yaptıklarına inanıyorum. HTTP ortamında performans için bunun gibi numaralar gerekli mi?
Simon_Weaver

ayrıca performans sorunları için stackoverflow.com/questions/2102591/…
Tim Abell

Yanıtlar:


764

Bunu severim:

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();

62
Önemli olan tek kök değişkeninden daha fazla genişleme konusunda dindar olmaktır. Her şey bundan akmalıdır.
annakata

22
Bu, kodunuz için bir kapatma oluşturmaz - diğer işlevlerinizi çağırmak sıkıcı hale gelir, çünkü her zaman aşağıdaki gibi görünmeleri gerekir: yourNamespace.bar (); Bu tasarım sorununu ele almak için SADECE açık kaynaklı bir proje yaptım: github.com/mckoss/namespace .
mckoss

24
annakata: "Önemli olan tek kök değişkeninden daha fazla genişleme konusunda dindar olmaktır." - Neden bu?
user406905 30:11

11
@alex - neden sığ bir nesne yapısı olmalı?
Ryan

25
@Ryan, her şeyin altında olması gerektiği anlamına geliyordum MyApp, örneğin ve MyApp.Views.Profile = {}yerine . Sadece iki seviye derinlik olması gerekmez. MyApp.users = {}MyViews.Profile = {}
alex

1042

Enterprise jQuery sitesinde bulunan yaklaşımı kullanıyorum :

Özel ve genel mülklerin ve işlevlerin nasıl bildirileceğini gösteren örnekleri aşağıda bulabilirsiniz. Her şey kendi kendini yürüten anonim bir işlev olarak yapılır.

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

Herkese açık üyelerden birine erişmek istiyorsanız skillet.fry()ya da gidin skillet.ingredients.

Gerçekten harika olan şey, artık tam olarak aynı sözdizimini kullanarak ad alanını genişletebilmenizdir.

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

Üçüncü undefinedargüman

Üçüncüsü, undefinedargüman değer değişkeninin kaynağıdır undefined. Bugün hala alakalı olup olmadığından emin değilim, ancak eski tarayıcılar / JavaScript standartları (ecmascript 5, javascript <1.8.5 ~ firefox 4) ile çalışırken, global kapsam değişkeni undefinedyazılabilir, böylece herkes değerini yeniden yazabilir. Üçüncü argüman (bir değer iletilmediğinde) undefinedad alanına / fonksiyonuna dahil edilen bir değişken oluşturur . Ad alanını oluşturduğunuzda hiçbir değer geçirilmediğinden, varsayılan olarak bu değerdir undefined.


9
Bu harika örnek için +1. İlgilenen herkes için, bu örnek Elijah Manor'un
Darren Lewis

11
Elijah'ın makalesinden, burada bu yaklaşımın artıları ve eksileri, yorumlanmıştır. Artıları: 1. Genel ve özel özellikleri ve yöntemleri, 2. hantal OLN kullanmaz, 3. undefined korur 4. $ jQuery anlamına gelir sağlar, 5. Ad alanı dosyaları kapsayabilir, Eksileri: OLN daha anlamak zor
Jared Beck

4
Buna bugün IIFE ( Hemen Çağrılan İşlev İfadesi ) denir . Cevabınız için teşekkürler +1!
Gustavo Gondim

20
@CpILL: hala alakalı olup olmadığından emin değilim, ancak üçüncü undefinedargüman, değer değişkeninin kaynağıdır undefined. Eski tarayıcılar / javascript standardıyla (ecmascript 5, javascript <1.8.5 ~ firefox 4) çalışırken, global kapsam değişkeni undefinedyazılabilir, böylece herkes değerini yeniden yazabilir. Üçüncü ve ek argüman eklemediğinizde değer katar undefined, böylece undefineddış kaynaklar tarafından yeniden yazılmayacak bir ad alanı kapsamı oluşturuyorsunuz .
mrówa

4
@SapphireSun Avantajı, window.skillet = window.skillet || {}birden fazla komut dosyasının hangi sırayla yürüteceklerini bilmediklerinde aynı ad alanına güvenli bir şekilde eklenmesine izin vermesidir . Kod eklemenizi keyfi olarak kodunuzu bozmadan yeniden sıralamak istiyorsanız veya komut dosyalarını zaman uyumsuz özellikle eşzamansız olarak yüklemek istiyorsanız ve bu nedenle yürütme sırası konusunda herhangi bir garantiniz yoksa bu yararlı olabilir. Bkz. Stackoverflow.com/questions/6439579/…
Mark Amery

338

Nesne hazır biçiminden biraz daha az kısıtlayıcı olduğunu düşündüğüm başka bir yol da şudur:

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

Yukarıdaki hemen hemen benzer modül desen ve bunun gibi olsun veya olmasın bir nesnesi değişmez katı yapısını kaçınırken, o herkese açık olarak tüm fonksiyonlarını ortaya çıkarmak için izin verir.


16
1. OLN ve modül modeli arasında bir fark vardır. 2. Son virgül koymamayı ve tüm özniteliklerinizin bir değerle (null veya undefined gibi) başlatılmasını hatırlamak zorunda olduğunuz için OLN'i sevmiyorum / her zaman / sevmiyorum. Ayrıca, üye işlevleri için kapatmalara ihtiyacınız varsa, bu yöntemlerin her biri için küçük işlev fabrikalarına ihtiyacınız olacaktır. Başka bir şey, tüm kontrol yapılarınızı fonksiyonların içine dahil etmeniz gerektiğidir, ancak yukarıdaki form bunu dayatmaz. Bu OLN kullanmadığım anlamına gelmiyor, sadece bazen sevmiyorum.
Ionuț G. Stan

8
Özel işlevleri, değişkenleri ve sözde sabitleri (yani var API_KEY = 12345;) sağlar çünkü bu yaklaşımı seviyorum.
Lawrence Barsanti

12
Ben daha yüksek oy alan virgülle ayrılmış nesne kapsayıcı daha iyi gibi. Karşılaştırmada da herhangi bir eksiklik görmüyorum. Bir şey mi kaçırıyorum?
Lucent

7
JS Newbie burada ... neden yazmam gerekmiyor ns().publicFunction(), yani ... ns.publicFunction()çalışıyor.
John Kraft

14
John Kraft, newanahtar kelimenin önündeki functionanahtar kelimeden kaynaklanıyor. Temel olarak, anonim bir işlev (ve bir işlev olarak bir yapıcı olduğu) bildirmesi ve ardından derhal onu kullanarak bir yapıcı olarak çağırmasıdır new. Bu nedenle, içinde depolanan son değer ns, anonim kurucunun (benzersiz) bir örneğidir. Umarım mantıklıdır.
Ionuț G. Stan

157

Bunu yapmanın daha zarif veya özlü bir yolu var mı?

Evet. Örneğin:

var your_namespace = your_namespace || {};

o zaman sahip olabilirsin

var your_namespace = your_namespace || {};
your_namespace.Foo = {toAlert:'test'};
your_namespace.Bar = function(arg) 
{
    alert(arg);
};
with(your_namespace)
{
   Bar(Foo.toAlert);
}

1
bu bana IE7'de bir hata veriyor. var your_namespace = (typeof your_namespace == "tanımsız" ||! your_namespace)? {}: ad alanınız; daha iyi çalışır.
mjallday

9
var olması gerekir ._namespace = your_namespace = your_namespace || {} Her tarayıcıda çalışır;)
Palo

Benden +1! İnce kitap, bir kitaplığı farklı dosyalara veya aynı dosya içindeki farklı yerlere genişleterek Jaco Pretorius yanıtı olarak çalışır. Sadece harika!
centurian

2
@Palo Lütfen neden böyle olması gerektiğini açıklayabilir misiniz? var your_namespace = your_namespace = your_namespace || {}
Sriram

6
your_namespace nesnesini farklı js dosyalarında genişletme olanağınız olur. Var your_namespace = {} kullanırken, nesne her dosya tarafından geçersiz
kılınacağı için bunu yapamazsınız

92

Ben normalde bir kapatma inşa:

var MYNS = MYNS || {};

MYNS.subns = (function() {

    function privateMethod() {
        // Do private stuff, or build internal.
        return "Message";
    }

    return {
        someProperty: 'prop value',
        publicMethod: function() {
            return privateMethod() + " stuff";
        }
    };
})();

Yıllar boyunca tarzım bunu yazdıktan sonra ince bir değişiklik geçirdi ve şimdi kendimi bu şekilde kapanışı yazarken buluyorum:

var MYNS = MYNS || {};

MYNS.subns = (function() {
    var internalState = "Message";

    var privateMethod = function() {
        // Do private stuff, or build internal.
        return internalState;
    };
    var publicMethod = function() {
        return privateMethod() + " stuff";
    };

    return {
        someProperty: 'prop value',
        publicMethod: publicMethod
    };
})();

Bu şekilde genel API ve uygulamayı daha kolay anlaşılır bulurum. İade ifadesini, uygulamaya genel bir arayüz olarak düşünün.


3
Kontrol etmemelisiniz MYNS.subns = MYNS.subns || {}??
Mirko

Geliştiricilerin niyetine alıştırma olması gereken iyi bir nokta. Var olduğunda ne yapacağınızı düşünmeniz, değiştirmeniz, hata yapmanız, var olan veya sürüm kontrolünü kullanmanız ve şartlı olarak değiştirmeniz gerekir. Her bir varyantı gerektiren farklı durumlar yaşadım. Çoğu durumda bunu düşük riskli bir durum olarak görüyorsunuz ve değiştirilmesi yararlı olabilir, NS'yi kaçırmaya çalışan sahte bir modül düşünün.
Brett Ryan

1
Bu yaklaşımın "Hızlı ve Kirli Modüller" başlığı altında 412 numaralı "Javascript Konuşması" kitabında bir açıklaması vardır.
Soferio

2
Optimizasyon ipucu: var foo = functionve function foobenzerken, özel olmak; JavaScript'in dinamik olarak yazılan doğası nedeniyle , çoğu yorumcunun boru hatlarında birkaç talimat atladığı için ikincisi biraz daha hızlıdır. Bununla birlikte var foo, tür sistemi, söz konusu var'a hangi türün atandığını bulmak için çağrılmalıdır function foo, ancak tür sistemi bunun bir işlev olduğunu otomatik olarak bilir, bu nedenle birkaç işlev çağrısı atlanır, bu da CPU komutlarının daha az çağrılmasına neden olur. jmp, pushq, popq, vs, daha kısa işlemci boru hattına çevirir hangi.
Braden Best

1
@ brett ayy. Haklısın. Farklı bir betik dili düşünüyordum. Yine de function foosözdiziminin daha okunabilir olduğu konusunda ısrar etsem de. Ve hala versiyonumu beğendim.
Braden Best

56

Farklı JavaScript dosyaları yazabileceğiniz ve daha sonra bunları bir uygulamada birleştirebileceğiniz veya birleştiremeyeceğiniz için, her birinin diğer alanların çalışmasına zarar vermeden ad alanı nesnesini kurtarabilmesi veya oluşturabilmesi gerekir ...

Bir dosya ad alanını kullanmayı düşünebilir namespace.namespace1:

namespace = window.namespace || {};
namespace.namespace1 = namespace.namespace1 || {};

namespace.namespace1.doSomeThing = function(){}

Başka bir dosya ad alanını kullanmak isteyebilir namespace.namespace2:

namespace = window.namespace || {};
namespace.namespace2 = namespace.namespace2 || {};

namespace.namespace2.doSomeThing = function(){}

Bu iki dosya çarpışmadan birlikte ya da ayrı yaşayabilir.


1
Ben bu işlevsellik modüler olması gereken büyük uygulamalarda birden fazla dosyaya istemci komut dosyası düzenlemek için çok yararlı bir yöntem olarak buldum.
DVK


48

Stoyan Stefanov'un, çok iyi bulduğum JavaScript Desenleri kitabında nasıl yaptığı (otomatik olarak oluşturulan API belgelerine izin veren yorumları nasıl yaptığını ve özel bir nesnenin prototipine nasıl bir yöntem ekleneceğini gösterir):

/**
* My JavaScript application
*
* @module myapp
*/

/** @namespace Namespace for MYAPP classes and functions. */
var MYAPP = MYAPP || {};

/**
* A maths utility
* @namespace MYAPP
* @class math_stuff
*/
MYAPP.math_stuff = {

    /**
    * Sums two numbers
    *
    * @method sum
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} Sum of the inputs
    */
    sum: function (a, b) {
        return a + b;
    },

    /**
    * Multiplies two numbers
    *
    * @method multi
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} The inputs multiplied
    */
    multi: function (a, b) {
        return a * b;
    }
};

/**
* Constructs Person objects
* @class Person
* @constructor
* @namespace MYAPP
* @param {String} First name
* @param {String} Last name
*/
MYAPP.Person = function (first, last) {

    /**
    * First name of the Person
    * @property first_name
    * @type String
    */
    this.first_name = first;

    /**
    * Last name of the Person
    * @property last_name
    * @type String
    */
    this.last_name = last;
};

/**
* Return Person's full name
*
* @method getName
* @return {String} First name + last name
*/
MYAPP.Person.prototype.getName = function () {
    return this.first_name + ' ' + this.last_name;
};

32

Bu yaklaşımı kullanıyorum:

var myNamespace = {}
myNamespace._construct = function()
{
    var staticVariable = "This is available to all functions created here"

    function MyClass()
    {
       // Depending on the class, we may build all the classes here
       this.publicMethod = function()
       {
          //Do stuff
       }
    }

    // Alternatively, we may use a prototype.
    MyClass.prototype.altPublicMethod = function()
    {
        //Do stuff
    }

    function privateStuff()
    {
    }

    function publicStuff()
    {
       // Code that may call other public and private functions
    }

    // List of things to place publically
    this.publicStuff = publicStuff
    this.MyClass = MyClass
}
myNamespace._construct()

// The following may or may not be in another file
myNamespace.subName = {}
myNamespace.subName._construct = function()
{
   // Build namespace
}
myNamespace.subName._construct()

Harici kod şu şekilde olabilir:

var myClass = new myNamespace.MyClass();
var myOtherClass = new myNamepace.subName.SomeOtherClass();
myNamespace.subName.publicOtherStuff(someParameter);

Güzel detay! Teşekkürler! Sadece Namespace.js'yi nasıl ele geçirdiğini merak ediyorum. Hiç kullanmadım, bu yüzden bilginiz / beceriniz / deneyiminiz olan birisinin kullanmayı düşünüp düşünmeyeceğini merak ediyorum.
John

Bunu sevdim! Öte yandan, bu dış kodun ilk satırında istisna alıyorum: 'myNameSpace.MyClass' [tanımsız] yapıcı değil. belki JS uygulamasına bağlıdır? : /
yoosiba

@yossiba: Muhtemelen. Yukarıdaki kod oldukça standart şeyler. Standart JS'de herhangi bir işlev yapıcı olarak kullanılabilir, bir işlevi özellikle yapıcı olarak kullanmak için işaretlemek için yapmanız gereken hiçbir şey yoktur. ActionScript gibi sıra dışı bir lezzet mi kullanıyorsunuz?
AnthonyWJones

@Anthony kullanmak daha iyi var MYNAMESPACE = MYNAMESPACE || {}; sadece var myNamespace = {} kullanmak güvensizdir ve ayrıca ad alanınızı büyük harflerle beyan etmek daha iyidir
paul

9
@paul: "Daha iyi" oldukça öznel olabilir. Bana büyük harf kullanan tanımlayıcıları kullanmaktan kaçınmak için bana SHOUTS okumaktan nefret ediyorum. İken ns = ns || {}kudretini diğer beklenmedik sonuçlara yol açabilir daha defansif görünüyor.
AnthonyWJones

32

Bu, user106826'nın Namespace.js bağlantısıdır. Proje GitHub'a taşınmış gibi görünüyor . Şimdi smith / namespacedotjs .

Küçük projem için bu basit JavaScript yardımcısını kullanıyorum ve şimdiye kadar hafif ama yine de ad alanı ve yükleme modülleri / sınıflarını idare edecek kadar çok yönlü görünüyor . Bir paketi, yalnızca global ad alanı değil, benim seçtiğim bir ad alanına içe aktarmama izin verirse harika olurdu ... iç çek, ama bu konunun dışında.

Ad alanını bildirmenize ve o ad alanındaki nesneleri / modülleri tanımlamanıza olanak tanır:

Namespace('my.awesome.package');
my.awesome.package.WildClass = {};

Başka bir seçenek de ad alanını ve içeriğini bir kerede bildirmektir:

Namespace('my.awesome.package', {
    SuperDuperClass: {
        saveTheDay: function() {
            alert('You are welcome.');
        }
    }
});

Daha fazla kullanım örneği için, kaynaktaki example.js dosyasına bakın .


2
Hatırladığınız sürece bazı performans sonuçları vardır, my.awesome.package.WildClass'a her eriştiğinizde, my.awesome'in paket özelliğine ve my.awesome'in WildClass özelliğine erişirsiniz. paketlemek.
SamStephens

29

Örneklem:

var namespace = {};
namespace.module1 = (function(){

    var self = {};
    self.initialized = false;

    self.init = function(){
        setTimeout(self.onTimeout, 1000)
    };

    self.onTimeout = function(){
        alert('onTimeout')
        self.initialized = true;
    };

    self.init(); /* If it needs to auto-initialize, */
    /* You can also call 'namespace.module1.init();' from outside the module. */
    return self;
})()

İsteğe bağlı olarak, özel olmasını istediğiniz gibi bir localdeğişkeni bildirebilir ve atayabilirsiniz .sameselflocal.onTimeout


14

Ad alanları sağlamak için basit bir işlev bildirebilirsiniz.

function namespace(namespace) {
    var object = this, tokens = namespace.split("."), token;

    while (tokens.length > 0) {
        token = tokens.shift();

        if (typeof object[token] === "undefined") {
            object[token] = {};
        }

        object = object[token];
    }

    return object;
}

// Usage example
namespace("foo.bar").baz = "I'm a value!";

13

Özel kapsama ihtiyacınız varsa:

var yourNamespace = (function() {

  //Private property
  var publicScope = {};

  //Private property
  var privateProperty = "aaa"; 

  //Public property
  publicScope.publicProperty = "bbb";

  //Public method
  publicScope.publicMethod = function() {
    this.privateMethod();
  };

  //Private method
  function privateMethod() {
    console.log(this.privateProperty);
  }

  //Return only the public parts
  return publicScope;
}());

yourNamespace.publicMethod();

özel kapsamı hiç kullanmayacaksanız:

var yourNamespace = {};

yourNamespace.publicMethod = function() {
    // Do something...
};

yourNamespace.publicMethod2 = function() {
    // Do something...
};

yourNamespace.publicMethod();

12

Modül modeli başlangıçta geleneksel yazılım mühendisliğindeki sınıflar için hem özel hem de genel kapsülleme sağlamanın bir yolu olarak tanımlanmıştır.

Modül deseni ile çalışırken, kullanmaya başlamak için kullandığımız basit bir şablon tanımlamayı yararlı bulabiliriz. İşte ad aralığı, genel ve özel değişkenleri kapsayan bir.

JavaScript'te Modül deseni, sınıf kavramını, hem genel / özel yöntemleri hem de değişkenleri tek bir nesnenin içine dahil edebileceğimiz ve böylece belirli bölümleri global kapsamdan koruyacak şekilde daha fazla taklit etmek için kullanılır. Bunun sonucu olarak, işlev adlarımızın sayfadaki ek komut dosyalarında tanımlanan diğer işlevlerle çakışması olasılığındaki bir azalma söz konusudur.

var myNamespace = (function () {

  var myPrivateVar, myPrivateMethod;

  // A private counter variable
  myPrivateVar = 0;

  // A private function which logs any arguments
  myPrivateMethod = function( foo ) {
      console.log( foo );
  };

  return {

    // A public variable
    myPublicVar: "foo",

    // A public function utilizing privates
    myPublicFunction: function( bar ) {

      // Increment our private counter
      myPrivateVar++;

      // Call our private method using bar
      myPrivateMethod( bar );

    }
  };

})();

Avantajları

Modül modeli neden iyi bir seçim? Yeni başlayanlar için, nesne odaklı bir arka plandan gelen geliştiriciler için, en azından bir JavaScript perspektifinden, gerçek kapsülleme fikrinden çok daha temiz.

İkincisi, özel verileri destekler - bu nedenle, Modül modelinde, kodumuzun genel bölümleri özel bölümlere dokunabilir, ancak dış dünya sınıfın özel bölümlerine dokunamaz.

Dezavantajları

Modül modelinin dezavantajları, hem genel hem de özel üyelere farklı eriştiğimizden, görünürlüğü değiştirmek istediğimizde, üyenin kullanıldığı her yerde aslında değişiklikler yapmamız gerektiğidir.

Özel üyelere daha sonra nesneye eklenen yöntemlerle de erişemeyiz . Bununla birlikte, birçok durumda Modül deseni hala oldukça yararlıdır ve doğru kullanıldığında, uygulamamızın yapısını geliştirme potansiyeline kesinlikle sahiptir.

Ortaya Çıkan Modül Modeli

Şimdi modül desenine biraz daha aşina olduğumuza göre, biraz geliştirilmiş bir versiyona bakalım - Christian Heilmann'ın Açığa Çıkarma Modülü deseni.

Açığa Çıkarma Modülü paterni, Heilmann'ın bir ortak yöntemi başka bir yöntemden çağırmak veya ortak değişkenlere erişmek istediğimizde ana nesnenin adını tekrarlamak zorunda kalmasıyla hayal kırıklığına uğradığı için ortaya çıktı. kamuoyuna açıklamak istediği şeyler için gerçek bir gösterime itiraz etmek.

Çabalarının sonucu, tüm işlevlerimizi ve değişkenlerimizi özel kapsamda basitçe tanımlayacağımız ve işaretçilerle anonim bir nesneyi halka açıklamak istediğimiz özel işlevselliğe geri döndüreceğimiz güncellenmiş bir kalıptı.

Açığa Çıkarma Modülünün nasıl kullanılacağına dair bir örnek aşağıda bulunabilir

var myRevealingModule = (function () {

        var privateVar = "Ben Cherry",
            publicVar = "Hey there!";

        function privateFunction() {
            console.log( "Name:" + privateVar );
        }

        function publicSetName( strName ) {
            privateVar = strName;
        }

        function publicGetName() {
            privateFunction();
        }


        // Reveal public pointers to
        // private functions and properties

        return {
            setName: publicSetName,
            greeting: publicVar,
            getName: publicGetName
        };

    })();

myRevealingModule.setName( "Paul Kinlan" );

Avantajları

Bu kalıp, komut dosyalarımızın sözdiziminin daha tutarlı olmasını sağlar. Modülün sonunda, hangi fonksiyon ve değişkenlerimizin halka açık olarak erişilebildiğini ve okunabilirliği kolaylaştırarak daha net hale getirir.

Dezavantajları

Bu modelin bir dezavantajı, özel bir işlev bir genel işleve başvuruyorsa, bir düzeltme ekinin gerekli olması durumunda bu genel işlevin geçersiz kılınamayacağıdır. Bunun nedeni, özel işlevin özel uygulamaya başvurmaya devam etmesi ve kalıbın genel üyeler için değil, yalnızca işlevler için geçerli olmasıdır.

Özel değişkenlere atıfta bulunan ortak nesne üyeleri de yukarıdaki yama olmayan kural notlarına tabidir.


9

Erlang'ın modüllerinden ilham alan bir isim alanı yarattım . Çok işlevsel bir yaklaşım, ama bu günlerde JavaScript kodumu böyle yazıyorum.

Bir kapamaya genel bir ad alanı verir ve bu kapama içinde tanımlı bir küme işlevi sunar.

(function(){

  namespace("images", previous, next);
  // ^^ This creates or finds a root object, images, and binds the two functions to it.
  // It works even though those functions are not yet defined.

  function previous(){ ... }

  function next(){ ... }

  function find(){ ... } // A private function

})();

8

Kütüphanelerimin birkaçını farklı projelere taşıdıktan ve sürekli olarak üst düzey (statik olarak adlandırılmış) ad alanını değiştirmek zorunda kaldıktan sonra, ad alanlarını tanımlamak için bu küçük (açık kaynak) yardımcı işlevini kullanmaya geçtim.

global_namespace.Define('startpad.base', function(ns) {
    var Other = ns.Import('startpad.other');
    ....
});

Avantajların açıklaması blog yayınımda . Sen yakala burada kaynak kodunu .

Gerçekten sevdiğim faydalardan biri, yük sırasına göre modüller arasında izolasyon. Harici bir modüle yüklenmeden ÖNCE başvurabilirsiniz. Kod alındığında aldığınız nesne referansı da doldurulacaktır.


1
Ad

tüm bağlantılarınız ölü gibi görünüyor
snoob dogg

8

Ad alanı için aşağıdaki sözdizimini kullanıyorum.

var MYNamespace = MYNamespace|| {};

 MYNamespace.MyFirstClass = function (val) {
        this.value = val;
        this.getValue = function(){
                          return this.value;
                       };
    }

var myFirstInstance = new MYNamespace.MyFirstClass(46);
alert(myFirstInstance.getValue());

jsfiddle: http://jsfiddle.net/rpaul/4dngxwb3/1/


8

Partiye 7 yıl geç kaldım, ancak bu 8 yıl önce biraz çalıştım:

JavaScript global ad alanına saygı gösterirken (ad alanı kirliliğini önler) karmaşık bir web uygulamasını düzenli ve yönetilebilir tutmak için kolay ve verimli bir şekilde birden fazla iç içe ad alanı oluşturabilmek ve bunu yaparken ad alanı yolunda varolan herhangi bir nesneyi engellememek önemlidir. .

Yukarıdakilerden, bu yaklaşık 2008 çözümümdü:

var namespace = function(name, separator, container){
  var ns = name.split(separator || '.'),
    o = container || window,
    i,
    len;
  for(i = 0, len = ns.length; i < len; i++){
    o = o[ns[i]] = o[ns[i]] || {};
  }
  return o;
};

Bu bir ad alanı oluşturmaz, ancak ad alanları oluşturmak için bir işlev sağlar.

Bu, minimize edilmiş bir astara yoğunlaştırılabilir:

var namespace=function(c,f,b){var e=c.split(f||"."),g=b||window,d,a;for(d=0,a=e.length;d<a;d++){g=g[e[d]]=g[e[d]]||{}}return g};

Kullanım örneği:

namespace("com.example.namespace");
com.example.namespace.test = function(){
  alert("In namespaced function.");
};

Veya tek bir ifade olarak:

namespace("com.example.namespace").test = function(){
  alert("In namespaced function.");
};

Her ikisi de şu şekilde yürütülür:

com.example.namespace.test();

Eski tarayıcılar için desteğe ihtiyacınız yoksa güncellenmiş bir sürüm:

const namespace = function(name, separator, container){
    var o = container || window;
    name.split(separator || '.').forEach(function(x){
        o = o[x] = o[x] || {};
    });
    return o;
};

Şimdi, namespaceküresel ad alanının kendisine maruz kalmanın temkinli olurum . (Çok kötü temel dil bunu bizim için sağlamaz!) Bu yüzden genellikle kendimi bir kapatmada kullanacağım, örneğin:

(function(){
	const namespace = function(name, separator, container){
		var o = container || window;
		name.split(separator || '.').forEach(function(x){
			o = o[x] = o[x] || {};
		});
		return o;
	};
	const ns = namespace("com.ziesemer.myApp");
	
	// Optional:
	ns.namespace = ns;
	
	// Further extend, work with ns from here...
}());

console.log("\"com\":", com);

Daha büyük bir uygulamada, bunun yalnızca sayfa yüklemesinin başlangıcında bir kez tanımlanması gerekir (istemci tabanlı web uygulamaları için). Daha sonra ek dosyalar tutulursa ad alanı işlevini yeniden kullanabilir (yukarıda "isteğe bağlı" olarak dahil edilmiştir). En kötüsü, bu işlev birkaç kez yeniden bildirilirse - sadece birkaç satır kod ve küçültüldüğünde daha az.


2

Jaco Pretorius'un çözümünü seviyorum, ancak "this" anahtar sözcüğünü modül / ad alanı nesnesine işaret ederek biraz daha kullanışlı hale getirmek istedim. Tava versiyonum:

(function ($, undefined) {

    console.log(this);

}).call(window.myNamespace = window.myNamespace || {}, jQuery);

2

En sevdiğim desen son zamanlarda şu oldu:

var namespace = (function() {
  
  // expose to public
  return {
    a: internalA,
    c: internalC
  }

  // all private
  
  /**
   * Full JSDoc
   */
  function internalA() {
    // ...
  }
  
  /**
   * Full JSDoc
   */
  function internalB() {
    // ...
  }
  
  /**
   * Full JSDoc
   */
  function internalC() {
    // ...
  }
  
  /**
   * Full JSDoc
   */
  function internalD() {
    // ...
  }
  
})();

Tabii ki, geri dönüş sonunda olabilir, ancak yalnızca işlev bildirimleri bunu izlerse, ad alanının ne olduğunu ve hangi API'nin maruz kaldığını görmek çok daha kolaydır.

Bu gibi durumlarda işlev ifadelerini kullanma düzeni, tüm kodun üzerinden geçmeden hangi yöntemlerin gösterildiğini bilmemeye neden olur.


Merhaba, snippet'inizden genel işlevleri nasıl çağırıyorsunuz? Denedimnamespace.a();
Olimart

@ olivier evet, fikir bu. Şimdi ES6 ile birlikte, genellikle nesne değişmezlerinin steno sözdizimini kullanıyorum ( ponyfoo.com/articles/es6-object-literal-features-in-depth )
Nomaed

2

Bence hepiniz böyle basit bir problem için çok fazla kod kullanıyorsunuz. Bunun için bir repo yapmaya gerek yok. İşte tek satırlık bir işlev.

namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);

Dene :

// --- definition ---
const namespace = namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);

// --- Use ----
let myNamespace = namespace("a.b.c");
myNamespace.MyClass = class MyClass {};

// --- see ----
console.log("a : ", a);


1

Makefile kullanıyorsanız bunu yapabilirsiniz.

// prelude.hjs
billy = new (
    function moduleWrapper () {
    const exports = this;

// postlude.hjs
return exports;
})();

// someinternalfile.js
function bob () { console.log('hi'); }
exports.bob = bob;

// clientfile.js
billy.bob();

Ben yaklaşık 1000 satır almak bir kez zaten bir Makefile kullanmayı tercih çünkü etkili bir şekilde makefile tek bir satır kaldırarak büyük kod alanlarını yorum olabilir. İşlerle uğraşmayı kolaylaştırır. Ayrıca, bu teknikle ad alanı yalnızca başlangıçta bir kez görünür, bu nedenle değiştirilmesi kolaydır ve bunu kitaplık kodunun içinde tekrarlamaya gerek yoktur.

Bir makefile kullanırken tarayıcıda canlı geliştirme için bir kabuk komut dosyası:

while (true); do make; sleep 1; done

Bunu bir make görevi 'go' olarak ekleyin ve kodunuzu oluştururken yapınızı güncel tutmak için 'go' yapabilirsiniz.


1

Ionuț G. Stan'ın cevabının oldukça takibi, ancak aynı koddaki var ClassFirst = this.ClassFirst = function() {...}sınıflar için daha az ad alanı dağınıklığı için JavaScript'in kapanma kapsamından yararlanan düzenli kodun faydalarını kullanarak gösteriyor .

var Namespace = new function() {
    var ClassFirst = this.ClassFirst = function() {
        this.abc = 123;
    }

    var ClassSecond = this.ClassSecond = function() {
        console.log("Cluttered way to access another class in namespace: ", new Namespace.ClassFirst().abc);
        console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
    }
}

var Namespace2 = new function() {
    var ClassFirst = this.ClassFirst = function() {
        this.abc = 666;
    }

    var ClassSecond = this.ClassSecond = function() {
        console.log("Cluttered way to access another class in namespace: ", new Namespace2.ClassFirst().abc);
        console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
    }
}

new Namespace.ClassSecond()
new Namespace2.ClassSecond()

Çıktı:

Cluttered way to access another class in namespace: 123
Nicer way to access a class in same namespace: 123
Cluttered way to access another class in namespace: 666
Nicer way to access a class in same namespace: 666

1

Biraz daha paketler / birimlerin diğer dillerde yaptığı gibi çalışan başka bir ad alanı kütüphanesi yazdım. Bir JavaScript kodu paketi ve bu paketin diğer koddan referansını oluşturmanıza izin verir:

Hello.js dosyası

Package("hello", [], function() {
  function greeting() {
    alert("Hello World!");
  }
  // Expose function greeting to other packages
  Export("greeting", greeting);
});

Örnek.js

Package("example", ["hello"], function(greeting) {
  // Greeting is available here
  greeting();  // Alerts: "Hello World!"
});

Yalnızca ikinci dosyanın sayfaya dahil edilmesi gerekir. Bağımlılıkları ( hello.js dosyası bu örnekte ) otomatik olarak yüklenecek ve bu bağımlılıklardan dışa aktarılan nesneler geri arama işlevinin bağımsız değişkenlerini doldurmak için kullanılacaktır.

İlgili projeyi Packages JS'de bulabilirsiniz .


1
@ peter-mortensen '11'den gelen cevabımda yapılan bu düzenlemeler gerçekten gerekli miydi? Yaptığınız şey kesinlikle vandalizm değil, beni yanlış anlamayın, ama bunlar çok yüzeysel. Gerçekten iyi bir şey eklemediğiniz sürece, bu tür yayınların tek yazarı olmayı tercih ederim.
Stijn de Witt

1

Bağımsız olarak bu şekilde kullanabiliriz:

var A = A|| {};
A.B = {};

A.B = {
    itemOne: null,
    itemTwo: null,
};

A.B.itemOne = function () {
    //..
}

A.B.itemTwo = function () {
    //..
}

0

Benim alışkanlığım özellik depolama olarak myName () işlevini kullanmak ve sonra "yöntem" tutucu olarak myName var ...

Bu yeterince meşru olsun ya da olmasın, beni döv! Ben her zaman PHP mantığına güveniyorum ve işler sadece çalışır. : D

function myObj() {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = 'string';
}

var myObj = (
 (myObj instanceof Function !== false)
 ? Object.create({

     $props: new myObj(),
     fName1: function() { /* code..  */ },
     fName2: function() { /* code ...*/ }
 })
 : console.log('Object creation failed!')
);

if (this !== that) myObj.fName1(); else myObj.fName2();

Nesne oluşturmadan önce kontrol etmek için 'tam tersi' bir şekilde de yapabilirsiniz; bu çok daha iyidir :

function myObj() {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = 'string';
}

var myObj = (
    (typeof(myObj) !== "function" || myObj instanceof Function === false)
    ? new Boolean()
    : Object.create({
        $props: new myObj(),
        init: function () { return; },
        fName1: function() { /* code..  */ },
        fName2: function() { /* code ...*/ }
    })
);

if (myObj instanceof Boolean) {
    Object.freeze(myObj);
    console.log('myObj failed!');
    debugger;
}
else
    myObj.init();

Buna referans: JavaScript: Object.create () ile Nesne Oluşturma


0

JavaScript'te ad alanlarını kullanmak için önceden tanımlanmış bir yöntem yoktur. JavaScript'te NameSpace'leri tanımlamak için kendi yöntemlerimizi oluşturmalıyız. İşte Oodles teknolojilerinde izlediğimiz bir prosedür.

Bir İsim Alanı Kaydetme Aşağıda, bir isim alanı kaydetme işlevi yer almaktadır

//Register NameSpaces Function
function registerNS(args){
 var nameSpaceParts = args.split(".");
 var root = window;

 for(var i=0; i < nameSpaceParts.length; i++)
 {
  if(typeof root[nameSpaceParts[i]] == "undefined")
   root[nameSpaceParts[i]] = new Object();

  root = root[nameSpaceParts[i]];
 }
}

Bir Ad Alanı kaydetmek için yukarıdaki işlevi bağımsız değişken '.'(nokta) ile ayırarak argümanla çağırmanız yeterlidir. Örneğin, Uygulama adınızın oodles olmasına izin verin. Aşağıdaki yöntemi kullanarak bir ad alanı oluşturabilirsiniz

registerNS("oodles.HomeUtilities");
registerNS("oodles.GlobalUtilities");
var $OHU = oodles.HomeUtilities;
var $OGU = oodles.GlobalUtilities;

Temel olarak, arka uçta aşağıdaki gibi NameSpaces yapınızı oluşturur:

var oodles = {
    "HomeUtilities": {},
    "GlobalUtilities": {}
};

Yukarıdaki işlevde "oodles.HomeUtilities"ve adında bir ad alanına sahip olursunuz "oodles.GlobalUtilities". Bu ad alanlarını çağırmak için bir değişken var yani var $OHUve var $OGU.

Bu değişkenler, ad alanını başlatan bir diğer ad değildir. Şimdi, size ait bir işlev bildirdiğinizde HomeUtilities, aşağıdaki gibi bildirir:

$OHU.initialization = function(){
    //Your Code Here
};

Yukarıda işlev adı başlatma ve bir ad alanına yerleştirilir $OHU. ve bu fonksiyonu kod dosyalarının herhangi bir yerine çağırmak. Sadece aşağıdaki kodu kullanın.

$OHU.initialization();

Benzer şekilde, başka bir NameSpaces ile.

Umarım yardımcı olur.


0

JavaScript varsayılan olarak ad alanını desteklemez. Eğer herhangi bir eleman (fonksiyon, yöntem, nesne, değişken) oluşturursanız, o zaman küresel hale gelir ve global isim alanını kirletir. Herhangi bir ad alanı olmadan iki işlevi tanımlamaya bir örnek verelim,

function func1() {
    console.log("This is a first definition");

}
function func1() {
    console.log("This is a second definition");
}
func1(); // This is a second definition

Her zaman ikinci işlev tanımını çağırır. Bu durumda ad alanı, ad çakışması sorununu çözecektir.

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.