JavaScriptで名前空間を宣言するにはどうすればよいですか?


990

オブジェクトと関数が他の同じ名前のオブジェクトと関数によって上書きされないように、JavaScriptで名前空間を作成するにはどうすればよいですか?私は以下を使用しました:

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

これを行うよりエレガントまたは簡潔な方法はありますか?


20
名前空間が使用されているかどうかを確認するためのチェックの場所を確認できますが、これが失敗するとオブジェクトが作成されないため、名前空間が使用されている場合に警告することをお勧めします。率直に言って、これはほとんどのJS状況では発生しないはずであり、開発ですぐに捕捉されるべきです。
アナカタ2009年

18
トップレベルの「名前空間」(ウィンドウプロパティ)を取ります。それを所有する。テストの早い段階で競合を検出する必要があります。これらすべての「what if」チェックを追加する必要はありません。これは重複する「名前空間」の致命的な問題であり、そのように扱う必要があります。jQueryのようなアプローチに従って、カスタムの「名前空間」を作成できます。しかし、これはまだ設計時の問題です。

受け入れられた回答を、よりエレガントで更新されたソリューションであるstackoverflow.com/questions/881515/…に変更してください。
hlfcoding

@pst YUIは何をしますか?名前空間に徐々に追加するために、まさにこれを行っていると思います。このようなトリックは、HTTP環境でのパフォーマンスに確実に必要ですか?
Simon_Weaver

パフォーマンスの問題については、stackoverflow.com / questions / 2102591 /…も参照してください
Tim Abell

回答:


764

私はこれが好き:

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();

62
重要な点は、1つのルート変数を超えて拡大しないことを信仰することです。これからすべてが流れなければなりません。
アナカタ2009年

22
これはコードのクロージャーを作成しません-他の関数は常に次のように見える必要があるため、他の関数を呼び出すのは面倒です:yourNamespace.bar(); この設計の問題に対処するために、オープンソースプロジェクトを作成しました:github.com/mckoss/namespace
mckoss 2011年

24
annakata:「重要な点は、1つのルート変数を超えて拡大しないことを信仰することです。」-これはなぜですか?
user406905

11
@alex-なぜ浅いオブジェクト構造が必要なのですか?
ライアン

25
@Ryan私はそのすべてが下にあるべきものでMyApp、例えばMyApp.Views.Profile = {}いうよりMyApp.users = {}MyViews.Profile = {}。必ずしも2つのレベルの深さがある必要はありません。
アレックス

1042

はEnterprise jQueryサイトにあるアプローチを使用します

以下は、プライベートおよびパブリックプロパティと関数を宣言する方法を示す例です。すべては、自己実行型の無名関数として行われます。

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

したがって、パブリックメンバーの1つにアクセスする場合は、単にアクセスするskillet.fry()か、skillet.ingredientsます。

本当にすばらしいのは、まったく同じ構文を使用して名前空間を拡張できることです。

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

3番目のundefined引数

3番目のundefined引数は、valueの変数のソースですundefined。今日でもまだ関連性があるかどうかはわかりませんが、古いブラウザー/ JavaScript標準(ecmascript 5、javascript <1.8.5〜firefox 4)を使用している場合、グローバルスコープ変数undefinedは書き込み可能であるため、誰でもその値を書き換えることができます。3番目の引数(値が渡されない場合)はundefined、名前空間/関数をスコープとするという名前の変数を作成します。名前空間の作成時に値が渡されなかったため、デフォルトで値が使用されますundefined


9
この素晴らしいサンプルの+1。興味のある人のために、このサンプルでは、ミックス2011でイライジャ・マナーの優れたプレゼンテーション(タイトルを無視する)の一部であったlive.visitmix.com/MIX11/Sessions/Speaker/Elijah-Manor
ダレン・ルイス

11
Elijahの記事から、このアプローチの長所と短所を以下に言い換えます。長所:1.パブリックおよびプライベートのプロパティとメソッド、2。面倒なOLNを使用しない、3。未定義を保護する4. $がjQueryを参照することを保証する、5。名前空間が複数のファイルにまたがることができる、短所:OLNよりも理解が難しい
Jared Beck

4
これは、今日IIFE即時に呼び出される関数式)と呼ばれます。回答ありがとうございます+1!
Gustavo Gondim 2013

20
@CpILL:まだ適切かどうかは不明ですが、3番目のundefined引数はvalueの変数のソースですundefined。古いブラウザ/ JavaScript標準(ecmascript 5、javascript <1.8.5〜firefox 4)で作業している間、グローバルスコープ変数undefinedは書き込み可能であるため、誰でもその値を書き換えることができます。渡していない3番目の引数を追加すると、値がvalue undefinedになるためundefined、外部ソースによって書き換えられない名前空間スコープを作成していました。
mrówa

4
@SapphireSunの利点window.skillet = window.skillet || {}は、複数のスクリプトが実行する順序が事前にわからない場合に、同じ名前空間に安全に追加できることです。これは、コードを壊すことなくスクリプトの包含を任意に並べ替えることができるようにする場合、またはasync属性を使用してスクリプトを非同期にロードする場合に、実行順序が保証されない場合に役立ちます。stackoverflow.com/questions/6439579/…を
Mark Amery

338

それを行う別の方法は、オブジェクトリテラルフォームよりも制限が少ないと私は考えていますが、これは次のとおりです。

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

上記のほとんどのようであるモジュールパターンあなたのこと好きかどうか、オブジェクトリテラルの剛性構造を回避しながら、それは、あなたがパブリックとして、すべての機能を公開することができます。


16
1. OLNとモジュールパターンには違いがあります。2.最後のコンマを入れないことを覚えておく必要があり、すべての属性を値(nullやundefinedなど)で初期化する必要があるため、OLNのように/ always /はしません。また、メンバー関数にクロージャーが必要な場合は、それらのメソッドごとに小さな関数ファクトリーが必要になります。もう1つのことは、すべての制御構造を関数内に含める必要があることですが、上記の形式はそれを強制しません。私がOLNを使用しないと言っているのではなく、たまにそれが気に入らない場合もあります。
Ionuț G. Stan

8
プライベート関数、変数、および疑似定数(var API_KEY = 12345;)を使用できるため、このアプローチが好きです。
Lawrence Barsanti

12
私は、これは、より多くの票を投じたコンマ区切りのオブジェクトコンテナーよりも優れています。比較しても欠点はありません。何か不足していますか?
Lucent

7
ここにJS初心者...と入力する必要がないのはなぜですかns().publicFunction()、つまり... ns.publicFunction()機能します。
John Kraft

14
@ジョンクラフト、それはnewキーワードの前にfunctionキーワードがあるためです。基本的に何をしているのかというと、それは無名関数を宣言し(そして関数として、それもコンストラクターです)、それからを使用してコンストラクターとしてすぐにそれを呼び出しますnew。そのため、内部に格納される最後の値nsは、その匿名コンストラクターの(一意の)インスタンスです。それが理にかなっていると思います。
Ionuț G. Stan

157

これを行うよりエレガントまたは簡潔な方法はありますか?

はい。例えば:

var your_namespace = your_namespace || {};

その後、あなたは持つことができます

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

1
これにより、IE7でエラーが発生します。var your_namespace =(typeof your_namespace == "undefined" ||!your_namespace)?{}:your_namespace; うまく機能します。
mjallday 2010年

9
var your_namespace = your_namespace = your_namespace || {}すべてのブラウザで動作します;)
Palo

私からの+1!シン1は、1つのライブラリを別のファイルまたは同じファイル内の別の場所に展開することにより、Jaco Pretoriusの応答として機能します。ただ素晴らしい!
センチュリアン

2
@パロなぜこんな風になるべきか説明してくれませんか?var your_namespace = your_namespace = your_namespace || {}
スリラム2013年

6
your_namespaceオブジェクトを別のjsファイルで拡張する可能性があります。var your_namespace = {}を使用する場合、オブジェクトは各ファイルによって上書きされるため、これを行うことはできません
Alex Pacurar

93

私は通常それをクロージャーに構築します:

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

これを書いてから何年にもわたって私のスタイルは微妙な変化を遂げており、今では次のようにクロージャーを書いています。

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

このようにして、パブリックAPIと実装が理解しやすくなります。returnステートメントは、実装へのパブリックインターフェイスであると考えてください。


3
確認してはいけませんかMYNS.subns = MYNS.subns || {}
Mirko

開発者の意図に沿った演習であるべき良い点。あなたはそれが存在するときに何をすべきかを考え、それを置き換え、エラーを起こし、既存またはバージョンチェックを使用し、条件付きで置き換える必要があります。各バリアントを必要とするさまざまな状況がありました。ほとんどの場合、これは低リスクのエッジケースである可能性があり、交換が有益な場合があります。NSを乗っ取ろうとした不正なモジュールを検討してください。
ブレット・ライアン

1
このアプローチの説明は、本の「Javascriptを話す」(412ページ)の「Quick and Dirty Modules」という見出しの下にあります。
Soferio 2015年

2
最適化のヒント:var foo = functionfunction fooは似ていますが、プライベートです。JavaScriptは動的に型付けされる性質のため、後者はほとんどのインタープリターのパイプラインでいくつかの命令をスキップするため、わずかに高速です。を使用するvar fooと、型システムは、そのvarに割り当てられている型を見つけるために呼び出される必要がありますが、を使用するfunction fooと、型システムはそれが関数であることを自動的に認識するため、2つの関数呼び出しがスキップされ、CPU命令の呼び出しが少なくなります。jmppushqpopq、など、短いCPUのパイプラインに変換しています。
ブレーデンベスト

1
@ブレットおっと。あなたが正しい。別のスクリプト言語を考えていました。私はまだfunction foo構文がより読みやすいと主張していますが。そして、私はまだ私のバージョンが好きです。
Braden Best

56

JavaScriptの異なるファイルを作成し、後でそれらをアプリケーションで組み合わせるか、または組み合わせない可能性があるため、それぞれが他のファイルの作業を損なうことなく名前空間オブジェクトを回復または構築できる必要があります...

1つのファイルで名前空間を使用する可能性がありますnamespace.namespace1

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

namespace.namespace1.doSomeThing = function(){}

別のファイルが名前空間を使用したい場合がありますnamespace.namespace2

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

namespace.namespace2.doSomeThing = function(){}

これらの2つのファイルは、衝突することなく、一緒にまたは離れて存在できます。


1
これは、機能をモジュール化する必要がある大規模なアプリケーションでクライアントスクリプトを複数のファイルに編成するための非常に便利な方法であることがわかりました。
DVK 2016

複数のファイルのために特別に尋ねる質問:stackoverflow.com/questions/5150124/...
チロSantilli冠状病毒审查六四事件法轮功

49

これは、Stoyan StefanovがJavaScriptパターンの本でどのように実行したかを示したものです(自動生成されたAPIドキュメントを可能にするコメントや、カスタムオブジェクトのプロトタイプにメソッドを追加する方法も示しています)。

/**
* 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

私はこのアプローチを使用します:

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

外部コードは次のようになります。

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

細かいディテール!ありがとう!Namespace.jsをどう思いますか。自分で使ったことがないので、知識やスキル、経験のある人が使ってみませんか。
John

私はそれが好きです!一方、この外部コードの最初の行で例外が発生し、「myNameSpace.MyClass」[undefined]はコンストラクターではありません。多分それはJSの実装に依存しますか?:/
yoosiba

@yossiba:たぶん。上記のコードはかなり標準的なものです。標準のJSでは、任意の関数をコンストラクターとして使用できます。特に、コンストラクターとして使用するために関数をマークする必要はありません。ActionScriptなどの珍しいフレーバーを使用していますか?
AnthonyWJones 2011

@Anthony var MYNAMESPACE = MYNAMESPACE ||を使用することをお勧めします {}; ただVaRのMYNAMESPACEを使用して= {}は大文字で名前空間を宣言するために、安全でない、しかもその方が良い
ポール・

9
@paul:「より良い」はかなり主観的です。私は大声で叫ぶコードを読むのが嫌いなので、すべて大文字を使用する識別子の使用は避けます。一方では、ns = ns || {}それが他の予期しない結果につながることができ、より守備のように見えるかもしれません。
AnthonyWJones 2011

32

これは、namespace.jsへのuser106826のリンクのフォローアップです。プロジェクトはGitHubに移動したようです。現在はsmith / namespacedotjsです。

私は小さなプロジェクトでこの単純なJavaScriptヘルパーを使用してきましたが、これまでのところ、名前空間の処理モジュール/クラスのロードを処理するのに十分なほど軽量で多用途なようです。グローバルな名前空間だけでなく、自分が選択した名前空間にパッケージをインポートできるようになれば素晴らしいです...ため息をつくだけでなく、それも重要です。

名前空間を宣言してから、その名前空間でオブジェクト/モジュールを定義できます。

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

別のオプションは、名前空間とその内容を一度に宣言することです:

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

その他の使用例については、ソースの example.jsファイルをご覧ください。


2
my.awesome.package.WildClassにアクセスするたびに、myの素晴らしいプロパティ、my.awesomeのパッケージプロパティ、およびmy.awesomeのWildClassプロパティにアクセスしているので、これがパフォーマンスに影響を与えることを覚えている限り。パッケージ。
SamStephens、2011

29

サンプル:

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

プライベートにしたい場合localsame、必要に応じて変数を宣言し、好きselfに割り当てlocal.onTimeoutます。


14

名前空間を提供する単純な関数を宣言できます。

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

プライベートスコープが必要な場合:

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

それ以外で、プライベートスコープを使用しない場合:

var yourNamespace = {};

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

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

yourNamespace.publicMethod();

12

Moduleパターンはもともと、従来のソフトウェアエンジニアリングのクラスにプライベートとパブリックの両方のカプセル化を提供する方法として定義されていました。

Moduleパターンを使用する場合、それを使い始めるために使用する単純なテンプレートを定義すると便利な場合があります。名前空間、パブリック変数、プライベート変数について説明します。

JavaScriptでは、モジュールパターンを使用してクラスのコンセプトをさらにエミュレートし、単一のオブジェクト内にパブリック/プライベートメソッドと変数の両方を含めることができるようにして、グローバルスコープから特定の部分を保護します。その結果、ページ上の追加のスクリプトで定義されている他の関数と関数名が競合する可能性が減少します。

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

    }
  };

})();

メリット

なぜモジュールパターンが良い選択なのですか?手始めに、少なくともJavaScriptの観点から見ると、オブジェクト指向のバックグラウンドを使用している開発者にとっては、真のカプセル化のアイデアよりもずっとクリーンです。

次に、プライベートデータをサポートします。したがって、モジュールパターンでは、コードのパブリック部分はプライベート部分にアクセスできますが、外部の世界はクラスのプライベート部分に触れることができません。

短所

モジュールパターンの欠点は、パブリックメンバーとプライベートメンバーの両方に異なる方法でアクセスするため、可視性を変更したい場合、メンバーが使用された各場所を実際に変更する必要があることです。

また、後でオブジェクトに追加されるメソッドのプライベートメンバーにアクセスすることもできません。とはいえ、多くの場合、モジュールパターンは依然として非常に有用であり、正しく使用すると、アプリケーションの構造を改善できる可能性があります。

明らかにするモジュールパターン

モジュールパターンに少し慣れたところで、少し改善されたバージョン、Christian HeilmannのRevealing Moduleパターンを見てみましょう。

公開モジュールパターンは、あるパブリックメソッドを別のメソッドから呼び出したり、パブリック変数にアクセスしたりするときにメインオブジェクトの名前を繰り返す必要があったという事実にハイルマンが苛立っていたために発生しました。彼が公表したかったものの文字表記に反対すること。

彼の努力の結果は、更新されたパターンであり、プライベートスコープですべての関数と変数を定義し、パブリックとして公開したいプライベート機能へのポインターを持つ匿名オブジェクトを返すだけでした。

表示モジュールパターンの使用例は以下にあります

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

メリット

このパターンにより、スクリプトの構文をより一貫させることができます。また、モジュールの最後で、どの関数と変数にパブリックにアクセスできるかが明確になり、読みやすくなります。

短所

このパターンの欠点は、プライベート関数がパブリック関数を参照する場合、パッチが必要な場合にそのパブリック関数をオーバーライドできないことです。これは、プライベート関数が引き続きプライベート実装を参照し、パターンがパブリックメンバーには適用されず、関数にのみ適用されるためです。

プライベート変数を参照するパブリックオブジェクトメンバーも、上記のパッチなしのルールに関する注意事項に従います。


9

名前空間を作成しましたErlangのモジュールに触発さ。これは非常に機能的なアプローチですが、私が最近JavaScriptコードを作成する方法です。

クロージャにグローバルな名前空間を与え、そのクロージャ内で定義されたセット関数を公開します。

(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

いくつかのライブラリをさまざまなプロジェクトに移植し、トップレベル(静的に名前が付けられた)名前空間を常に変更する必要があるため、名前空間を定義するためにこの小さな(オープンソース)ヘルパー関数を使用するように切り替えました。

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

利点の説明は私のブログ投稿にあります。ここでソースコードを入手できます

私が本当に好きな利点の1つは、ロード順序に関してモジュール間を分離することです。ロードする前に外部モジュールを参照できます。そして、コードが利用可能になると、取得したオブジェクト参照が入力されます。


1
:私は、名前空間ライブラリの改良版(2.0)作成した code.google.com/p/pageforest/source/browse/appengine/static/src/...
mckoss

すべてのリンクが機能していないようです
snoob dogg

8

名前空間には次の構文を使用します。

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

私はパーティーに7年遅れていますが、この8年前にかなりの作業をしました。

JavaScriptグローバルネームスペースを尊重しながら(ネームスペースの汚染を防止)、ネームスペースパス内の既存のオブジェクトを壊さないようにしながら、複雑なWebアプリケーションを整理して管理しやすいように、複数のネストされたネームスペースを簡単かつ効率的に作成できることが重要です。 。

上記から、これは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;
};

これは名前空間を作成するのではなく、名前空間を作成するための機能を提供します。

これは縮小されたワンライナーに凝縮することができます:

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

使用例:

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

または、1つのステートメントとして:

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

次に、どちらかが次のように実行されます。

com.example.namespace.test();

レガシーブラウザのサポートが必要ない場合は、更新されたバージョン:

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

さて、私namespaceはグローバルな名前空間自体にさらされることはありません。(ベース言語がこれを提供しないのは残念です!)したがって、私は通常、次のようなクロージャーでこれを自分で使用します。

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

より大きなアプリケーションでは、これはページのロードの開始時に一度だけ定義する必要があります(クライアントベースのWebアプリの場合)。追加のファイルは、保持されている場合、ネームスペース関数を再利用できます(上記では「オプション」として含まれています)。最悪の場合、この関数が数回再宣言された場合-それは数行のコードであり、縮小された場合は少なくなります。


3

私は皆さんがそのような単純な問題に多すぎるコードを使用していると思います。そのためのリポジトリを作成する必要はありません。これが単一行関数です。

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

それを試してみてください :

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


2

私はJaco Pretoriusのソリューションが好きですが、「this」キーワードをモジュール/名前空間オブジェクトにポイントすることで、もう少し有用なものにしたいと考えました。私のバージョンのスキレット:

(function ($, undefined) {

    console.log(this);

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

2

私のお気に入りのパターンは最近これになりました:

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

もちろん、最後にreturnを置くこともできますが、関数宣言だけがそれに続く場合は、名前空間とは何か、どのAPIが公開されているかを確認する方がはるかに簡単です。

このような場合に関数式を使用するパターンでは、コード全体を調べないと、どのメソッドが公開されているかを知ることができません。


こんにちは、スニペットからパブリック関数をどのように呼び出しますか?私が試したnamespace.a();
olimart

@olivierはい、それがアイデアです。現在はES6を使用していますが、通常はオブジェクトリテラル(ponyfoo.com/articles/es6-object-literal-features-in-depth)の省略構文を使用します
Nomaed

1

Makefileを使用している場合は、これを行うことができます。

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

とにかく、約1000行に達したらMakefileを使用することを好みます。なぜなら、Makefile内の1行を削除することで、コードの大きなスワスを効果的にコメントアウトできるからです。それはものをいじるのを簡単にします。また、この手法では、名前空間はプレリュードに一度だけ表示されるため、簡単に変更でき、ライブラリコード内で名前空間を繰り返す必要はありません。

makefileを使用するときにブラウザでライブ開発するためのシェルスクリプト:

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

これをmakeタスクの 'go'として追加すると、 'make go'を実行して、コーディング時にビルドを更新し続けることができます。


1

Ionuț G. Stanの回答のかなりのフォローアップですがvar ClassFirst = this.ClassFirst = function() {...}、を使用してコードが整理されていることの利点を示しています。これは、同じ名前空間内のクラスの名前空間の整理のためにJavaScriptのクロージャスコープを利用しています。

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

出力:

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

他の言語でパッケージ/ユニットが行うようにもう少し機能する別の名前空間ライブラリを作成しました。JavaScriptコードのパッケージを作成し、そのパッケージを他のコードから参照することができます。

ファイルhello.js

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

ファイルExample.js

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

2番目のファイルのみをページに含める必要があります。その依存関係(ファイルhello.jsこの例では)が自動的にロードされ、それらの依存関係からエクスポートされたオブジェクトを使用して、コールバック関数の引数が設定されます。

関連するプロジェクトはPackages JSにあります。


1
@ peter-mortensen '11からの私の回答に対するこれらの編集は本当に必要でしたか?それは間違いなく破壊行為ではありません。誤解しないでください。しかし、それは表面的なものです。あなたが本当に良いものを追加しない限り、私はこれらのような投稿の唯一の著者であり続けることを望みます。
Stijn de Witt

1

次のように、独立して使用できます。

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

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

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

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

0

私の習慣は、関数myName()をプロパティストレージとして使用し、次に変数myNameを「メソッド」ホルダーとして使用することです...

これで十分かどうかにかかわらず、私を倒してください!私はいつも私のPHPロジックに依存しており、物事は単純に機能します。: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();

また、オブジェクトの作成前に確認するために「逆の方法」で行うこともできます

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

これへの参照:JavaScript:Object.create()によるオブジェクトの作成


0

JavaScriptでは、名前空間を使用するための事前定義されたメソッドはありません。JavaScriptでは、名前空間を定義する独自のメソッドを作成する必要があります。Oodlesテクノロジーで従う手順は次のとおりです。

名前空間の登録以下は名前空間を登録する機能です

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

名前空間を登録するには、上記の関数を'.'(ドット)で区切られた名前空間として引数を指定して呼び出します。たとえば、アプリケーション名をoodlesとします。以下の方法で名前空間を作成できます

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

基本的には、バックエンドに以下のようなNameSpaces構造を作成します。

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

上記の関数では"oodles.HomeUtilities"、and という名前空間を登録しています"oodles.GlobalUtilities"。これらの名前空間を呼び出すには、変数、つまりvar $OHUとvar を作成します$OGU

これらの変数は、名前空間を初期化するためのエイリアスにすぎません。今、HomeUtilitiesあなたが属している関数を宣言するときはいつでも、次のようにそれを宣言します:

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

上記は関数名の初期化であり、名前空間に配置されます$OHU。そして、スクリプトファイル内の任意の場所でこの関数を呼び出します。次のコードを使用してください。

$OHU.initialization();

同様に、別の名前空間。

それが役に立てば幸い。


0

JavaScriptはデフォルトでは名前空間をサポートしていません。したがって、要素(関数、メソッド、オブジェクト、変数)を作成すると、その要素はグローバルになり、グローバルネームスペースを汚染します。名前空間なしで2つの関数を定義する例を見てみましょう。

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

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

常に2番目の関数定義を呼び出します。この場合、名前空間は名前の衝突問題を解決します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.