Bagaimana cara mendeklarasikan namespace dalam JavaScript?

990

Bagaimana cara membuat namespace di JavaScript sehingga objek dan fungsi saya tidak ditimpa oleh objek dan fungsi lain yang bernama sama? Saya telah menggunakan yang berikut ini:

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

Apakah ada cara yang lebih elegan atau ringkas untuk melakukan ini?

Scott McKenzie
sumber
20
Saya bisa melihat ke mana Anda akan pergi dengan memeriksa untuk melihat apakah namespace diambil, tetapi karena objek tidak akan dibuat jika ini gagal saya pikir pendekatan yang lebih baik adalah untuk mengingatkan jika namespace diambil. Terus terang ini seharusnya tidak terjadi di sebagian besar situasi JS dan harus ditangkap dengan cepat dalam pengembangan.
annakata
18
Ambil "namespace" tingkat atas (properti jendela). Memilikinya. Konflik harus dideteksi sejak awal dalam pengujian. Jangan repot-repot menambahkan semua cek "bagaimana jika" ini. Ini adalah masalah fatal untuk duplikat "ruang nama" dan harus diperlakukan seperti itu . Anda dapat mengikuti pendekatan seperti jQuery untuk memungkinkan menghuni "namespace" khusus; tapi ini masih merupakan masalah waktu desain.
Silakan ubah jawaban yang Anda terima ke stackoverflow.com/questions/881515/… , yang merupakan solusi yang jauh lebih elegan dan diperbarui.
hlfcoding
@ pst, bagaimana dengan apa yang YUI lakukan? Saya percaya mereka melakukan ini untuk menambah ruang nama mereka secara bertahap. Trik seperti ini diperlukan untuk kinerja di lingkungan HTTP?
Simon_Weaver
lihat juga stackoverflow.com/questions/2102591/... untuk masalah kinerja
Tim Abell

Jawaban:

764

Saya suka ini:

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();
dfa
sumber
62
Poin penting adalah menjadi religius tentang ekspansi tidak lebih dari satu variabel root. Semuanya harus mengalir dari sini.
annakata
22
Ini tidak membuat penutupan untuk kode Anda - itu membuatnya membosankan untuk memanggil fungsi lain Anda karena mereka selalu harus terlihat seperti: yourNamespace.bar (); Saya membuat proyek open source HANYA untuk mengatasi masalah desain ini: github.com/mckoss/namespace .
mckoss
24
annakata: "Poin penting adalah menjadi religius tentang ekspansi tidak lebih dari satu variabel root." - Mengapa ini?
user406905
11
@alex - mengapa harus ada struktur objek yang dangkal?
Ryan
25
@Ryan saya maksudkan bahwa semuanya harus di bawah MyApp, misalnya MyApp.Views.Profile = {}daripada MyApp.users = {}dan MyViews.Profile = {}. Tidak harus hanya kedalaman dua tingkat saja.
alex
1042

Saya menggunakan pendekatan yang ditemukan di situs Enterprise jQuery :

Berikut ini adalah contoh mereka yang menunjukkan cara mendeklarasikan properti dan fungsi pribadi & publik. Semuanya dilakukan sebagai fungsi anonim yang dijalankan sendiri.

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

Jadi jika Anda ingin mengakses salah satu anggota publik Anda hanya akan pergi skillet.fry()atau skillet.ingredients.

Apa yang benar-benar keren adalah bahwa Anda sekarang dapat memperluas namespace menggunakan sintaks yang sama persis.

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

undefinedArgumen ketiga

undefinedArgumen ketiga adalah sumber dari variabel nilai undefined. Saya tidak yakin apakah itu masih relevan hari ini, tetapi ketika bekerja dengan browser / standar JavaScript yang lebih lama (ecmascript 5, javascript <1.8.5 ~ firefox 4), variabel lingkup global undefineddapat ditulis, sehingga siapa pun dapat menulis ulang nilainya. Argumen ketiga (ketika tidak melewati nilai) membuat variabel bernama undefinedyang dicakup ke namespace / fungsi. Karena tidak ada nilai yang diteruskan ketika Anda membuat ruang nama, itu default ke nilai undefined.

Jaco Pretorius
sumber
9
+1 untuk sampel hebat ini. Bagi siapa pun yang tertarik, sampel ini adalah bagian dari presentasi istimewa Elijah Manor di Mix 2011 (abaikan judulnya) live.visitmix.com/MIX11/Sessions/Speaker/Elijah-Manor
Darren Lewis
11
Dari artikel Elia, berikut adalah pro dan kontra dari pendekatan ini, diparafrasekan. Kelebihan: 1. Properti dan metode publik dan swasta, 2. tidak menggunakan OLN yang rumit, 3. Melindungi tidak terdefinisi 4. Memastikan bahwa $ merujuk ke jQuery, 5. Namespace dapat merentang file, Kontra: Lebih sulit dipahami daripada OLN
Jared Beck
4
Ini disebut hari ini IIFE ( Ekspresi Fungsi yang Segera Diminta ). Terima kasih atas jawaban Anda +1!
Gustavo Gondim
20
@CpILL: tidak yakin apakah masih relevan, tetapi undefinedargumen ketiga, adalah sumber dari variabel nilai undefined. Saat bekerja dengan standar browser / javascript yang lebih lama (ecmascript 5, javascript <1.8.5 ~ firefox 4), variabel lingkup global undefineddapat ditulis, sehingga siapa pun dapat menulis ulang nilainya. Menambahkan ketiga, argumen tambahan yang tidak Anda lewati membuatnya bernilai undefined, jadi Anda membuat namespace-scope undefinedyang tidak akan ditulis ulang oleh sumber luar.
mrówa
4
@SapphireSun Manfaatnya window.skillet = window.skillet || {}adalah memungkinkan beberapa skrip ditambahkan dengan aman ke namespace yang sama ketika mereka tidak tahu sebelumnya dalam urutan apa yang akan mereka jalankan. Ini dapat membantu jika Anda ingin dapat menyusun ulang penyertaan skrip Anda secara sewenang-wenang tanpa melanggar kode Anda, atau jika Anda ingin memuat skrip secara asinkron dengan atribut async sehingga tidak memiliki jaminan tentang urutan eksekusi. Lihat stackoverflow.com/questions/6439579/…
Mark Amery
338

Cara lain untuk melakukannya, yang saya anggap sedikit kurang membatasi daripada bentuk objek literal, adalah ini:

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

Di atas cukup seperti pola modul dan apakah Anda suka atau tidak , itu memungkinkan Anda untuk mengekspos semua fungsi Anda sebagai publik, sambil menghindari struktur kaku objek literal.

Ionuț G. Stan
sumber
16
1. Ada perbedaan antara OLN dan pola modul. 2. Saya tidak / selalu / suka OLN karena Anda harus ingat untuk tidak menaruh koma trailing terakhir dan semua atribut Anda harus diinisialisasi dengan nilai (seperti nol atau tidak terdefinisi). Juga, jika Anda memerlukan penutupan untuk fungsi anggota, Anda akan memerlukan pabrik fungsi kecil untuk masing-masing metode tersebut. Hal lain adalah bahwa Anda harus menyertakan semua struktur kontrol Anda di dalam fungsi, sedangkan bentuk di atas tidak memaksakan itu. Itu bukan untuk mengatakan bahwa saya tidak menggunakan OLN, hanya saja kadang-kadang saya tidak menyukainya.
Ionuț G. Stan
8
Saya suka pendekatan ini karena memungkinkan untuk fungsi pribadi, variabel, dan konstanta pseudo (yaitu var API_KEY = 12345;).
Lawrence Barsanti
12
Saya suka ini lebih baik daripada wadah objek yang dipisahkan koma yang memilih lebih tinggi. Saya juga tidak melihat kekurangan dalam perbandingan. Apakah saya melewatkan sesuatu?
Lucent
7
JS Newbie di sini ... mengapa saya tidak perlu mengetik ns().publicFunction(), yaitu ... ns.publicFunction()berfungsi.
John Kraft
14
@ John Kraft, ini karena newkata kunci di depan functionkata kunci. Pada dasarnya, apa yang dilakukan adalah mendeklarasikan fungsi anonim (dan sebagai fungsi, ia juga merupakan konstruktor), dan kemudian segera memanggilnya sebagai konstruktor menggunakan new. Dengan demikian, nilai akhir yang disimpan di dalamnya nsadalah instance (unik) dari konstruktor anonim itu. Semoga itu masuk akal.
Ionuț G. Stan
157

Apakah ada cara yang lebih elegan atau ringkas untuk melakukan ini?

Iya. Sebagai contoh:

var your_namespace = your_namespace || {};

maka kamu dapat memiliki

var your_namespace = your_namespace || {};
your_namespace.Foo = {toAlert:'test'};
your_namespace.Bar = function(arg) 
{
    alert(arg);
};
with(your_namespace)
{
   Bar(Foo.toAlert);
}
Alex Pacurar
sumber
1
ini memberi saya kesalahan dalam IE7. var your_namespace = (ketik your_namespace == "undefined" ||! your_namespace)? {}: your_namespace; bekerja lebih baik.
mjallday
9
itu harus var your_namespace = your_namespace = your_namespace || {} Berfungsi di setiap browser;)
Palo
+1 dari saya! Yang tipis berfungsi sebagai jawaban Jaco Pretorius dengan memperluas satu pustaka ke file yang berbeda atau tempat yang berbeda di dalam file yang sama. Sangat brilian!
centurian
2
@Palo Bisakah Anda jelaskan mengapa harus seperti ini? var your_namespace = your_namespace = your_namespace || {}
Sriram
6
Anda akan memiliki kemungkinan untuk memperluas objek your_namespace di file js berbeda. Saat menggunakan var your_namespace = {} Anda tidak bisa melakukan itu, karena objek akan ditimpa oleh setiap file
Alex Pacurar
93

Saya biasanya membangunnya sebagai penutup:

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

Gaya saya selama bertahun-tahun telah mengalami perubahan yang halus sejak menulis ini, dan sekarang saya menemukan diri saya menulis penutupan seperti ini:

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

Dengan cara ini saya menemukan API publik dan implementasi lebih mudah dimengerti. Pikirkan pernyataan kembali sebagai antarmuka publik untuk implementasi.

Brett Ryan
sumber
3
Jika Anda tidak memeriksa MYNS.subns = MYNS.subns || {}??
Mirko
Poin bagus yang harus menjadi latihan untuk niat pengembang. Anda perlu mempertimbangkan apa yang harus dilakukan ketika ada, ganti, galat, gunakan yang ada atau versi periksa dan ganti dengan kondisi. Saya memiliki situasi berbeda yang membutuhkan setiap varian. Dalam kebanyakan kasus, Anda mungkin memiliki ini sebagai kasing tepi risiko rendah dan mengganti dapat bermanfaat, pertimbangkan modul jahat yang mencoba membajak NS.
Brett Ryan
1
Ada penjelasan tentang pendekatan ini dalam Buku "Speaking Javascript" di halaman 412 jika ada yang memilikinya, di bawah judul "Modul Cepat dan Kotor".
Soferio
2
Kiat pengoptimalan: sementara var foo = functiondan function fooserupa, bersifat pribadi; karena sifat JavaScript yang diketik secara dinamis, yang terakhir ini sedikit lebih cepat karena melompati beberapa instruksi di sebagian besar saluran pipa juru bahasa. Dengan var foo, sistem jenis harus dipanggil untuk mencari tahu jenis apa yang ditugaskan untuk kata var, sementara dengan function foo, sistem jenis secara otomatis tahu itu adalah fungsi, jadi beberapa panggilan fungsi dilewati, yang diterjemahkan menjadi lebih sedikit permintaan instruksi CPU seperti jmp, pushq, popq, dll, yang diterjemahkan ke pipa CPU lebih pendek.
Braden Best
1
@ brett oops. Kamu benar. Saya sedang memikirkan bahasa scripting yang berbeda. Meskipun saya masih bersikeras bahwa function foosintaks lebih mudah dibaca. Dan saya masih suka versi saya.
Braden Best
56

Karena Anda dapat menulis file JavaScript yang berbeda dan kemudian menggabungkan atau tidak menggabungkannya dalam aplikasi, masing-masing harus dapat memulihkan atau membangun objek namespace tanpa merusak karya file lain ...

Satu file mungkin bermaksud menggunakan namespace namespace.namespace1:

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

namespace.namespace1.doSomeThing = function(){}

File lain mungkin ingin menggunakan namespace namespace.namespace2:

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

namespace.namespace2.doSomeThing = function(){}

Kedua file ini dapat hidup bersama atau terpisah tanpa bertabrakan.

Fentex
sumber
1
Saya telah menemukan ini menjadi metode yang sangat berguna untuk mengatur skrip klien ke dalam beberapa file dalam aplikasi besar di mana fungsi perlu modular.
DVK
Pertanyaan yang diajukan secara khusus untuk beberapa file: stackoverflow.com/questions/5150124/…
Ciro Santilli 郝海东 冠状 病 六四 事件 事件
49

Inilah cara Stoyan Stefanov melakukannya di buku Pola Javascript yang menurut saya sangat bagus (ini juga menunjukkan bagaimana ia melakukan komentar yang memungkinkan dokumentasi API yang dibuat secara otomatis, dan cara menambahkan metode ke prototipe objek khusus):

/**
* 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;
};
Ciaran Bruen
sumber
32

Saya menggunakan pendekatan ini:

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

Kode eksternal dapat berupa:

var myClass = new myNamespace.MyClass();
var myOtherClass = new myNamepace.subName.SomeOtherClass();
myNamespace.subName.publicOtherStuff(someParameter);
AnthonyWJones
sumber
Detail besar! Terima kasih! Hanya ingin tahu apa pendapat Anda tentang Namespace.js. Saya tidak pernah menggunakannya sendiri, jadi saya ingin tahu apakah seseorang dengan pengetahuan / keterampilan / pengalaman Anda akan mempertimbangkan untuk menggunakannya.
John
Saya suka itu! Di sisi lain saya mendapatkan pengecualian pada baris pertama dari kode eksternal ini, dengan mengatakan: 'myNameSpace.MyClass' [tidak terdefinisi] bukan konstruktor. mungkin itu tergantung pada implementasi JS? : /
yoosiba
@Yossiba: Mungkin. Kode di atas adalah hal yang cukup standar. Dalam JS standar fungsi apa pun dapat digunakan sebagai konstruktor, tidak ada yang perlu Anda lakukan untuk menandai fungsi secara khusus untuk digunakan sebagai konstruktor. Apakah Anda menggunakan rasa yang tidak biasa seperti ActionScript atau sesuatu?
AnthonyWJones
@Anthony lebih baik menggunakan var MYNAMESPACE = MYNAMESPACE || {}; hanya menggunakan var myNamespace = {} tidak aman dan lebih baik mendeklarasikan namespace Anda dalam huruf besar
paul
9
@ paul: "Lebih baik" bisa sangat subjektif. Saya benci membaca kode yang SHOUTS pada saya, jadi saya menghindari menggunakan pengidentifikasi yang menggunakan semua huruf besar. Sementara ns = ns || {}mungkin tampak lebih defensif, itu dapat menyebabkan hasil yang tidak terduga lainnya.
AnthonyWJones
32

Ini adalah tindak lanjut dari tautan user106826 ke Namespace.js. Sepertinya proyek pindah ke GitHub . Sekarang smith / namespacedotjs .

Saya telah menggunakan bantuan JavaScript sederhana ini untuk proyek kecil saya dan sejauh ini tampaknya ringan namun cukup fleksibel untuk menangani namespacing dan memuat modul / kelas. Akan lebih bagus jika itu akan memungkinkan saya untuk mengimpor paket ke namespace pilihan saya, bukan hanya namespace global ... huh, tapi itu intinya.

Ini memungkinkan Anda untuk mendeklarasikan namespace kemudian mendefinisikan objek / modul di namespace itu:

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

Pilihan lain adalah mendeklarasikan namespace dan isinya sekaligus:

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

Untuk contoh penggunaan lainnya, lihat file example.js di sumber .

Rudy Lattae
sumber
2
Selama Anda ingat ini memiliki beberapa implikasi kinerja, karena setiap kali Anda mengakses my.awesome.package.WildClass Anda mengakses properti mengagumkan saya, properti paket my.awesome, dan properti WildClass dari my.awesome. paket.
SamStephens
29

Sampel:

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

Anda dapat mendeklarasikan localvariabel same,, suka, selfdan tetapkan secara opsional local.onTimeoutjika Anda ingin itu bersifat pribadi.

Jim Jose
sumber
14

Anda dapat mendeklarasikan fungsi sederhana untuk menyediakan ruang nama.

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!";
dnemoga
sumber
13

Jika Anda membutuhkan ruang lingkup pribadi:

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

lain jika Anda tidak akan pernah menggunakan ruang lingkup pribadi:

var yourNamespace = {};

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

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

yourNamespace.publicMethod();
Tadej
sumber
12

Pola Modul awalnya didefinisikan sebagai cara untuk menyediakan enkapsulasi pribadi dan publik untuk kelas dalam rekayasa perangkat lunak konvensional.

Ketika bekerja dengan pola Module, kita mungkin menemukan manfaat untuk mendefinisikan template sederhana yang kita gunakan untuk memulainya. Berikut ini salah satu yang mencakup spasi nama, variabel publik dan pribadi.

Dalam JavaScript, pola Module digunakan untuk lebih meniru konsep kelas sedemikian rupa sehingga kami dapat memasukkan metode publik / pribadi dan variabel di dalam objek tunggal, sehingga melindungi bagian-bagian tertentu dari lingkup global. Hasilnya adalah pengurangan kemungkinan nama fungsi kami bertentangan dengan fungsi lain yang didefinisikan dalam skrip tambahan pada halaman.

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

    }
  };

})();

Keuntungan

mengapa pola Modul merupakan pilihan yang baik? Sebagai permulaan, ini jauh lebih bersih bagi pengembang yang datang dari latar belakang berorientasi objek daripada gagasan enkapsulasi sejati, setidaknya dari perspektif JavaScript.

Kedua, ini mendukung data pribadi - jadi, dalam pola Modul, bagian publik dari kode kami dapat menyentuh bagian pribadi, namun dunia luar tidak dapat menyentuh bagian pribadi kelas.

Kekurangan

Kerugian dari pola Modul adalah ketika kita mengakses anggota publik dan swasta secara berbeda, ketika kita ingin mengubah visibilitas, kita sebenarnya harus membuat perubahan di setiap tempat anggota itu digunakan.

Kami juga tidak dapat mengakses anggota pribadi dalam metode yang ditambahkan ke objek di kemudian hari . Yang mengatakan, dalam banyak kasus, pola Modul masih cukup berguna dan ketika digunakan dengan benar, tentu memiliki potensi untuk meningkatkan struktur aplikasi kita.

Pola Penyingkapan Modul

Sekarang kita sedikit lebih terbiasa dengan pola modul, mari kita lihat versi yang sedikit lebih baik - pola Revealing Module milik Christian Heilmann.

Pola Revealing Module muncul ketika Heilmann frustrasi dengan fakta bahwa ia harus mengulangi nama objek utama ketika kami ingin memanggil satu metode publik dari yang lain atau mengakses variabel publik. Ia juga tidak menyukai persyaratan pola Modul karena harus beralih untuk menolak notasi literal untuk hal-hal yang ingin dipublikasikan.

Hasil dari usahanya adalah pola yang diperbarui di mana kami hanya akan mendefinisikan semua fungsi dan variabel kami dalam lingkup pribadi dan mengembalikan objek anonim dengan petunjuk ke fungsi pribadi yang ingin kami ungkapkan sebagai publik.

Contoh cara menggunakan pola Modul Penyingkapan dapat ditemukan di bawah

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

Keuntungan

Pola ini memungkinkan sintaks skrip kami menjadi lebih konsisten. Itu juga membuatnya lebih jelas di akhir modul mana dari fungsi dan variabel kita dapat diakses secara publik yang memudahkan keterbacaan.

Kekurangan

Kerugian dari pola ini adalah bahwa jika fungsi privat mengacu pada fungsi publik, fungsi publik itu tidak dapat diganti jika tambalan diperlukan. Ini karena fungsi privat akan terus merujuk pada implementasi privat dan polanya tidak berlaku untuk anggota publik, hanya untuk fungsi.

Anggota objek publik yang merujuk ke variabel pribadi juga tunduk pada catatan aturan no-patch di atas.

Divyanshu Rawat
sumber
9

Saya membuat namespace yang terinspirasi oleh modul Erlang. Ini adalah pendekatan yang sangat fungsional, tapi itulah cara saya menulis kode JavaScript saya hari ini.

Ini memberikan penutupan namespace global dan mengekspos fungsi set yang didefinisikan dalam penutupan itu.

(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

})();
WHO
sumber
8

Setelah porting beberapa perpustakaan saya ke proyek yang berbeda, dan harus terus-menerus mengubah tingkat atas (nama statis) namespace, saya telah beralih menggunakan fungsi pembantu kecil (open source) untuk mendefinisikan ruang nama.

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

Deskripsi manfaat ada di posting blog saya . Anda dapat mengambil kode sumber di sini .

Salah satu manfaat yang sangat saya sukai adalah isolasi antar modul sehubungan dengan urutan pemuatan. Anda dapat merujuk ke modul eksternal SEBELUM itu dimuat. Dan referensi objek yang Anda dapatkan akan diisi ketika kode tersedia.

mckoss
sumber
1
Saya telah membuat versi yang disempurnakan (2.0) dari perpustakaan namespace: code.google.com/p/pageforest/source/browse/appengine/static/src/…
mckoss
semua tautan Anda tampaknya mati
snoob dogg
8

Saya menggunakan sintaks berikut untuk namespace.

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/

Razan Paul
sumber
8

Saya terlambat 7 tahun ke pesta, tetapi melakukan sedikit pekerjaan sekitar 8 tahun yang lalu:

Penting untuk dapat dengan mudah dan efisien membuat beberapa ruang nama bersarang untuk menjaga aplikasi web yang kompleks terorganisir dan dikelola, sambil menghormati JavaScript namespace global (mencegah pencemaran namespace), dan dengan tidak mengalahkan benda apa pun yang ada di jalur namespace saat melakukan hal itu .

Dari penjelasan di atas, ini adalah solusi saya sekitar tahun 2008:

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;
};

Ini bukan menciptakan namespace, tetapi menyediakan fungsi untuk membuat namespace.

Ini dapat diringkas ke liner satu minified:

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};

Contoh penggunaan:

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

Atau, sebagai satu pernyataan:

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

Keduanya kemudian dieksekusi sebagai:

com.example.namespace.test();

Jika Anda tidak memerlukan dukungan untuk browser lawas, versi yang diperbarui:

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

Sekarang, saya akan ragu mengekspos namespaceke namespace global itu sendiri. (Sayang sekali bahasa dasar tidak menyediakan ini untuk kami!) Jadi saya biasanya menggunakan ini sendiri sebagai penutup, seperti:

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

Dalam aplikasi yang lebih besar, ini hanya perlu didefinisikan sekali pada awal pemuatan halaman (untuk aplikasi web berbasis klien). File tambahan kemudian dapat menggunakan kembali fungsi namespace jika disimpan (disertakan sebagai "opsional" di atas). Paling buruk, jika fungsi ini dinyatakan ulang beberapa kali - itu hanya beberapa baris kode, dan lebih sedikit jika diperkecil.

ziesemer
sumber
3

Saya pikir Anda semua menggunakan terlalu banyak kode untuk masalah sederhana. Tidak perlu membuat repo untuk itu. Inilah fungsi garis tunggal.

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

Cobalah :

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

Yairopro
sumber
2

Saya suka solusi Jaco Pretorius, tetapi saya ingin membuat kata kunci "ini" sedikit lebih berguna dengan mengarahkannya ke objek module / namespace. Versi wajan saya:

(function ($, undefined) {

    console.log(this);

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

Pola favorit saya menjadi belakangan ini:

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() {
    // ...
  }
  
})();

Tentu saja, return bisa di bagian akhir, tetapi jika hanya deklarasi fungsi yang mengikutinya, akan lebih mudah untuk melihat apa itu namespace, dan apa yang diekspos API.

Pola penggunaan ekspresi fungsi dalam kasus-kasus seperti itu mengakibatkan tidak dapat mengetahui metode apa yang terbuka tanpa membahas seluruh kode.

Tidak ada
sumber
Hai, bagaimana Anda memanggil fungsi publik dari cuplikan Anda? Saya sudah mencobanamespace.a();
olimart
@olivier ya, itulah idenya. Meskipun sekarang dengan ES6, saya biasanya menggunakan sintaks singkatan dari objek literal ( ponyfoo.com/articles/es6-object-literal-features-in-depth )
Nomaed
1

Jika menggunakan Makefile Anda dapat melakukan ini.

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

Saya lebih suka menggunakan Makefile setelah saya mendapatkan sekitar 1000 baris karena saya dapat secara efektif mengomentari sejumlah besar kode dengan menghapus satu baris di makefile. Itu membuatnya mudah untuk mengutak-atik barang. Juga, dengan teknik ini namespace hanya muncul sekali di awal sehingga mudah untuk diubah dan Anda tidak harus terus mengulanginya di dalam kode perpustakaan.

Skrip shell untuk pengembangan langsung di browser saat menggunakan makefile:

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

Tambahkan ini sebagai tugas make 'go' dan Anda bisa 'make go' untuk menjaga build Anda diperbarui saat Anda membuat kode.

Samuel Danielson
sumber
1

Cukup tindak lanjut dari jawaban Ionuț G. Stan, tetapi menunjukkan manfaat dari kode yang tidak berantakan dengan menggunakan var ClassFirst = this.ClassFirst = function() {...}, yang mengambil keuntungan dari pelingkupan penutupan JavaScript untuk mengurangi keruwetan namespace untuk kelas di namespace yang sama.

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

Keluaran:

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
lama12345
sumber
1

Saya telah menulis perpustakaan namespacing lain yang bekerja sedikit lebih seperti paket / unit lakukan dalam bahasa lain. Ini memungkinkan Anda untuk membuat paket kode JavaScript dan referensi paket itu dari kode lain:

File hello.js

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

File Example.js

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

Hanya file kedua yang perlu dimasukkan dalam halaman. Ketergantungannya (file hello.js dalam contoh ini) akan secara otomatis dimuat dan objek yang diekspor dari dependensi tersebut akan digunakan untuk mengisi argumen fungsi panggilan balik.

Anda dapat menemukan proyek terkait di Paket JS .

Stijn de Witt
sumber
1
@ peter-mortensen Apakah pengeditan ini untuk jawaban saya dari '11 benar-benar diperlukan? Ini jelas bukan vandalisme apa yang Anda lakukan, jangan salah paham, tetapi mereka sangat dangkal. Saya lebih suka tetap menjadi penulis tunggal posting seperti ini kecuali jika Anda benar-benar menambahkan sesuatu yang baik.
Stijn de Witt
1

Kita dapat menggunakannya secara mandiri dengan cara ini:

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

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

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

A.B.itemTwo = function () {
    //..
}
Ganesh
sumber
0

Kebiasaan saya adalah menggunakan fungsi myName () sebagai penyimpanan properti, dan kemudian var myName sebagai pemegang "metode" ...

Apakah ini cukup sah atau tidak, pukul saya! Saya mengandalkan logika PHP saya sepanjang waktu, dan semuanya berjalan dengan baik. : 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();

Anda juga dapat melakukannya dengan cara 'sebaliknya' untuk memeriksa sebelum pembuatan objek yang jauh lebih baik :

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

Referensi untuk ini: JavaScript: Membuat Objek dengan Object.create ()

Menyeramkan
sumber
0

Dalam JavaScript tidak ada metode yang telah ditentukan untuk menggunakan ruang nama. Dalam JavaScript kita harus membuat metode sendiri untuk mendefinisikan NameSpaces. Berikut adalah prosedur yang kami ikuti dalam teknologi Oodles.

Mendaftarkan NameSpace Berikut adalah fungsi untuk mendaftarkan ruang nama

//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]];
 }
}

Untuk mendaftarkan Namespace, panggil fungsi di atas dengan argumen sebagai ruang nama yang dipisahkan oleh '.'(titik). Sebagai Contoh Biarkan nama aplikasi Anda adalah jumlah besar sekali. Anda dapat membuat namespace dengan metode berikut

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

Pada dasarnya itu akan membuat struktur NameSpaces Anda seperti di bawah ini di backend:

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

Dalam fungsi di atas Anda telah mendaftarkan namespace yang dipanggil "oodles.HomeUtilities"dan "oodles.GlobalUtilities". Untuk memanggil ruang nama ini kami membuat variabel yaitu var $OHUdan var $OGU.

Variabel-variabel ini tidak lain adalah alias untuk Menginternalisasi namespace. Sekarang, Setiap kali Anda mendeklarasikan fungsi milik HomeUtilitiesAnda, akan mendeklarasikannya seperti berikut:

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

Di atas adalah inisialisasi nama fungsi dan dimasukkan ke dalam namespace $OHU. dan untuk memanggil fungsi ini di mana saja dalam file skrip. Cukup gunakan kode berikut.

$OHU.initialization();

Demikian pula dengan NameSpaces yang lain.

Semoga ini bisa membantu.

Saurabh tiwary
sumber
0

JavaScript tidak mendukung namespace secara default. Jadi jika Anda membuat elemen apa pun (fungsi, metode, objek, variabel) maka itu menjadi global dan mencemari namespace global. Mari kita ambil contoh mendefinisikan dua fungsi tanpa namespace,

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

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

Itu selalu memanggil definisi fungsi kedua. Dalam hal ini, namespace akan menyelesaikan masalah nama tabrakan.

vishu2124
sumber