2010-08-05 14 views
15

Chcę utworzyć globalną przestrzeń nazw dla mojej aplikacji iw tej przestrzeni nazw chcę mieć inne przestrzenie nazw:JavaScript Namespace

Na przykład:

Dashboard.Ajax.Post() 

Dashboard.RetrieveContent.RefreshSalespersonPerformanceContent(); 

Chcę również, aby umieścić je w oddzielnych plikach:

  • Ajax.js
  • RetrieveContent.js

Jednak Próbowałem, używając this metody, jednak to won” t działa, ponieważ ta sama nazwa zmiennej jest używana w przestrzeni nazw w 2 oddzielnych miejscach. Czy ktoś może zaoferować alternatywę?

Dzięki.

+0

Nazwa przestrzeni nazw coś inaczej? –

+0

Sądzę, że jest to jedna opcja, jednak miałem nadzieję, że uwzględnię wszystko pod jedną przestrzenią nazw, ponieważ myślałem, że będzie bardziej uporządkowana w ten sposób. –

Odpowiedz

1

Można zrobić coś takiego ...

strona HTML przy użyciu przestrzeni nazw Biblioteka:

<html> 
<head> 
    <title>javascript namespacing</title> 
    <script src="dashboard.js" type="text/javascript"></script> 
    <script src="ajax.js" type="text/javascript"></script> 
    <script src="retrieve_content.js" type="text/javascript"></script> 
    <script type="text/javascript"> 
     alert(Dashboard.Ajax.Post()); 
     alert(Dashboard.RetrieveContent.RefreshSalespersonPerformanceContent()); 
     Dashboard.RetrieveContent.Settings.Timeout = 1500; 
     alert(Dashboard.RetrieveContent.Settings.Timeout); 
    </script> 
</head> 

<body> 
    whatever... 
</body> 

</html> 

Dashboard.js:

(function(window, undefined){ 
    var dashboard = {}; 
    window.Dashboard = dashboard; 
})(window); 

Ajax.js:

(function(){ 
    var ajax = {}; 
    ajax.Post = function() { return "Posted!" }; 
    window.Dashboard.Ajax = ajax 
})(); 

Retrieve_Content.js:

(function(){ 
    var retrieveContent = {}; 
    retrieveContent.RefreshSalespersonPerformanceContent = function() { 
     return "content retrieved" 
    }; 


    var _contentType; 
    var _timeout; 
    retrieveContent.Settings = { 
     "ContentType": function(contentType) { _contentType = contentType; }, 
     "ContentType": function() { return _contentType; }, 
     "Timeout": function(timeout) { _timeout = timeout; }, 
     "Timeout": function() { return _timeout; } 
    }; 

    window.Dashboard.RetrieveContent = retrieveContent; 

})(); 

Dashboard.js działa jako punkt wyjścia dla wszystkich nazw pod nią. Pozostałe są zdefiniowane w odpowiednich plikach. W pliku Retrieve_Content.js dodałem kilka dodatkowych właściwości pod numerem Settings, aby dać wyobrażenie, jak to zrobić, w razie potrzeby.

+0

Nie ma gwarancji, że 'retrieve_content.js' zostanie załadowany i przeanalizowany po' Dashboard.js'. Jeśli którakolwiek z bibliotek zależnych zostanie załadowana przed wczytaniem 'Dashboard.js', to przypisania się nie powiedzie. –

+1

Ogólnie "Dashboard.js" zostanie załadowany i przeanalizowany jako pierwszy, ale tak, to nie jest gwarantowane. Obiekt 'Dashboard' może być sprawdzony przed przypisaniem i utworzony w razie potrzeby, ale wymagałoby to zduplikowanego kodu w' retrieve_content.js' i 'ajax.js'. Oddzielne wymagania plików PO doprowadziły mnie do powyższego. – ironsam

4

Funkcja Yahoo Namespace jest dokładnie zaprojektowana dla tego problemu.

Dodano:

source funkcji jest niedostępna. Możesz go skopiować do własnego kodu, jeśli chcesz, zmień root z YAHOO na coś innego, itd.

9

Musisz tylko upewnić się, że nie nadepniesz na twój obiekt przestrzeni nazw, jeśli został już utworzony. Coś jak to będzie działać:

(function() { 
    // private vars can go in here 


    Dashboard = Dashboard || {}; 
    Dashboard.Ajax = { 
     Post: function() { 
      ... 
     } 
    }; 
})(); 

a plik RetrieveContent byłoby zdefiniowane podobnie.

+0

Witam, próbuję umieścić mój kod również w przestrzeniach nazw, ale mam jedno pytanie: Mam dużo plików JavaScript, czy powinienem dodać 'Dashboard = Dashboard || {}; '(jeśli to byłby mój obszar nazw) przy każdym pliku? A po drugie, czy muszę wstawiać każdą zmienną do Dashboard.x zamiast X, czy nie jest to konieczne, ponieważ wszystko żyje w tej samej przestrzeni nazw? – Michel

3

Istnieje kilka bibliotek, które już oferują ten rodzaj funkcjonalności, jeśli chcesz użyć lub sprawdzić wstępnie upieczone (to znaczy przetestowane) rozwiązanie.

Najprostszym i najbardziej wolny od błędów jeden dostać się z to prawdopodobnie jQuery.extend, z Argument deep ustawiono na true. (Powodem, dla którego mówię, że jest wolny od błędów, nie jest to, że uważam, że jQuery.extend cierpi na mniej błędów niż jakakolwiek inna biblioteka - ale dlatego, że oferuje wyraźną opcję głębokiego kopiowania atrybutów od nadawcy do odbiorcy - z czego większość inne biblioteki nie udostępniają tego w sposób oczywisty, co uniemożliwi wiele trudnych do zdiagnozowania błędów w twoim programie, ponieważ użyłeś płytkiej kopii extend i teraz masz funkcje wykonywane w kontekstach, których nie oczekiwałeś. Wykonując w. (Jeśli jednak wiesz, jak rozszerzyć bibliotekę podstawową podczas projektowania metod, nie powinno to stanowić problemu.)

1

Wierzę, że wzór modułu może być zaraz za tobą. artykuł dotyczący różnych wzorów modułów

http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

+0

Odpowiedzi za pomocą odpowiednich linków nie są przydatne. Tutaj powinno być dość wyjaśnienia. Pytanie brzmi: jak definiować obiekty w przestrzeniach nazw z dwóch różnych lokalizacji –

+1

@JuanMendes: Artykuł dokładnie to wyjaśnia. Kilka z najlepszych odpowiedzi to po prostu również linki. Poza tym to było ponad półtora roku temu. –

+0

Nigdy tak naprawdę nie znalazłem wzoru modułu, który byłby odpowiedni dla przestrzeni nazw. Przestrzeń nazw nie jest blokiem kodu "wielokrotnego użytku" (choć poszczególne części NS mogą być). Literały obiektowe zawsze działały dla mnie wystarczająco dobrze. – 1nfiniti

3

Z obiektu NS stworzonej, należy po prostu być w stanie dodać do niego skąd kiedykolwiek. Chociaż możesz chcieć wypróbować var NS = NS || {};, aby upewnić się, że obiekt NS istnieje i nie jest nadpisany.

// NS is a global variable for a namespace for the app's code 
var NS = NS || {}; 

NS.Obj = (function() { 

    // Private vars and methods always available to returned object via closure 
    var foo; // ... 

    // Methods in here are public 
    return { 
    method: function() { 

    } 
    }; 

}()); 
1

Gorąco polecam użyć tej techniki:

https://github.com/mckoss/namespace

namespace.lookup('com.mydomain.mymodule').define(function (ns) { 
    var external = namespace.lookup('com.domain.external-module'); 

    function myFunction() { 
    ... 
    } 

    ... 

    ns.extend({ 
    'myFunction': myFunction, 
    ... 
    }); 
}); 

Używam tego wzoru na kilka lat; Żałuję, że więcej bibliotek nie zrobiłoby tego samego; znacznie ułatwiło mi udostępnianie kodu w różnych moich projektach.

7

Here to bardzo dobry artykuł na temat różnych "Wzorów modułów" w JavaScript. Istnieje bardzo ładna sekcja, w której można rozszerzyć moduły lub przestrzenie nazw i zachować stan prywatny między plikami. Oznacza to, że kod w osobnych plikach będzie wykonywany sekwencyjnie i odpowiednio powiększy przestrzeń nazw po jej wykonaniu.

Nie badałem dokładnie tej techniki, więc nie ma obietnic ... ale tu jest podstawowa idea.

dashboard.js

(function(window){ 

    var dashboard = (function() { 
     var my = {}, 
      privateVariable = 1; 

     function privateMethod() { 
      // ... 
     } 

     my.moduleProperty = 1; 
     my.moduleMethod = function() { 
      // ... 
     }; 

     return my; 
    }()); 

    window.Dashboard = dashboard; 
})(window); 

dashboard.ajax.js

var dashboard = (function (my) { 
    var _private = my._private = my._private || {}, 
     _seal = my._seal = my._seal || function() { 
      delete my._private; 
      delete my._seal; 
      delete my._unseal; 
     }, 
     _unseal = my._unseal = my._unseal || function() { 
      my._private = _private; 
      my._seal = _seal; 
      my._unseal = _unseal; 
     }; 

    // permanent access to _private, _seal, and _unseal 

    my.ajax = function(){ 
     // ... 
    } 

    return my; 
}(dashboard || {})); 

dashboard.retrieveContent.js

var dashboard = (function (my) { 
    var _private = my._private = my._private || {}, 
     _seal = my._seal = my._seal || function() { 
      delete my._private; 
      delete my._seal; 
      delete my._unseal; 
     }, 
     _unseal = my._unseal = my._unseal || function() { 
      my._private = _private; 
      my._seal = _seal; 
      my._unseal = _unseal; 
     }; 

    // permanent access to _private, _seal, and _unseal 

    my.retrieveContent = function(){ 
     // ... 
    } 

    return my; 
}(dashboard || {})); 
+0

Czy możesz mi wyjaśnić, w jaki sposób umożliwia to dostęp do zmiennych prywatnych zadeklarowanych w innym pliku? Bardziej szczegółowe, jeśli mam wywołać dashboard._seal(), w jaki sposób dashboard._unseal() pozwala mi ponownie uzyskać dostęp do prywatnego? –

0

bob.js może pomóc w określeniu swoich nazw (między innymi):

bob.ns.setNs('Dashboard.Ajax', { 

    Post: function() { /*...*/ } 
}); 

bob.ns.setNs('Dashboard.RetrieveContent', { 

    RefreshSalespersonPerformanceContent: function() { /*...*/ } 
}); 
1

napisałem tę funkcję, aby uprościć tworzenie nazw. Mabey to ci pomoże.

function ns(nsstr) { 
    var t = nsstr.split('.'); 
    var obj = window[t[0]] = window[t[0]] || {}; 
    for (var i = 1; i < t.length; i++) { 
     obj[t[i]] = obj[t[i]] || {}; 
     obj = obj[t[i]]; 
    } 
} 

ns('mynamespace.isawesome.andgreat.andstuff'); 
mynamespace.isawesome.andgreat.andstuff = 3; 

console.log(mynamespace.isawesome.andgreat.andstuff); 
0

Realizacja:

namespace = function(packageName) 
{ 
    // Local variables. 
    var layers, layer, currentLayer, i; 

    // Split the given string into an array. 
    // Each element represents a namespace layer. 
    layers = packageName.split('.'); 

    // If the top layer does not exist in the global namespace. 
    if (eval("typeof " + layers[0]) === 'undefined') 
    { 
     // Define the top layer in the global namesapce. 
     eval(layers[0] + " = {};"); 
    } 

    // Assign the top layer to 'currentLayer'. 
    eval("currentLayer = " + layers[0] + ";"); 

    for (i = 1; i < layers.length; ++i) 
    { 
     // A layer name. 
     layer = layers[i]; 

     // If the layer does not exist under the current layer. 
     if (!(layer in currentLayer)) 
     { 
      // Add the layer under the current layer. 
      currentLayer[layer] = {}; 
     } 

     // Down to the next layer. 
     currentLayer = currentLayer[layer]; 
    } 

    // Return the hash object that represents the last layer. 
    return currentLayer; 
}; 


Wynik:

namespace('Dashboard.Ajax').Post = function() { 
    ...... 
}; 

namespace('Dashboard.RetrieveContent').RefreshSalespersonPerformanceContent = function() { 
    ...... 
}; 


Gi st:

namespace.js

Powiązane problemy