オブジェクトと関数が他の同じ名前のオブジェクトと関数によって上書きされないように、JavaScript で名前空間を作成するにはどうすればよいですか? 私は以下を使用しました:
if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}
これを行うためのよりエレガントまたは簡潔な方法はありますか?
オブジェクトと関数が他の同じ名前のオブジェクトと関数によって上書きされないように、JavaScript で名前空間を作成するにはどうすればよいですか? 私は以下を使用しました:
if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}
これを行うためのよりエレガントまたは簡潔な方法はありますか?
I use the approach found on the Enterprise jQuery site:
Here is their example showing how to declare private & public properties and functions. Everything is done as a self-executing anonymous function.
(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 ));
So if you want to access one of the public members you would just go skillet.fry() or skillet.ingredients.
What's really cool is that you can now extend the namespace using the exact same syntax.
//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 ));
undefined argument3 番目の
undefined引数は、 value の変数のソースですundefined。今日でも関連性があるかどうかはわかりませんが、古いブラウザー/JavaScript 標準 (ecmascript 5、javascript < 1.8.5 ~ firefox 4) を使用している間、グローバル スコープ変数undefinedは書き込み可能であるため、誰でもその値を書き換えることができます。undefined3 番目の引数 (値が渡されない場合) は、名前空間/関数をスコープとする名前付き変数を作成します。名前空間を作成したときに値が渡されなかったため、デフォルトで value に設定されますundefined。
私はこれが好き:
var yourNamespace = {
foo: function() {
},
bar: function() {
}
};
...
yourNamespace.foo();
それを行う別の方法は、オブジェクトリテラル形式よりも少し制限が少ないと私が考えるものですが、これは次のとおりです。
var ns = new function() {
var internalFunction = function() {
};
this.publicFunction = function() {
};
};
上記はモジュール パターンによく似ており、好むと好まざるとにかかわらず、オブジェクト リテラルの厳密な構造を回避しながら、すべての関数をパブリックとして公開できます。
これを行うためのよりエレガントまたは簡潔な方法はありますか?
はい。例えば:
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);
}
私は通常、クロージャーでそれを構築します:
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 ステートメントは、実装へのパブリック インターフェイスであると考えてください。
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つのファイルは、衝突することなく共存または分離できます。
これは、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;
};
これは、user106826 の Namespace.js へのリンクのフォローアップです。プロジェクトはGitHubに移動したようです。現在はsmith/namespacedotjsです。
私はこの単純な JavaScript ヘルパーを自分の小さなプロジェクトに使用してきましたが、これまでのところ、名前空間の処理とモジュール/クラスのロードを処理するのに十分な軽量でありながら用途が広いようです。グローバル名前空間だけでなく、自分の選択した名前空間にパッケージをインポートできるようになれば素晴らしいことですが... はぁ、それは問題外です。
名前空間を宣言してから、その名前空間でオブジェクト/モジュールを定義できます。
Namespace('my.awesome.package');
my.awesome.package.WildClass = {};
もう 1 つのオプションは、名前空間とその内容を一度に宣言することです。
Namespace('my.awesome.package', {
SuperDuperClass: {
saveTheDay: function() {
alert('You are welcome.');
}
}
});
その他の使用例については、ソースの example.js ファイルを参照してください。
サンプル:
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;
})()
プライベートにしたい場合は、必要に応じてlocal変数を宣言しsame、 likeselfおよび assignすることができます。local.onTimeout
名前空間を提供する単純な関数を宣言できます。
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!";
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
})();
私はパーティーに 7 年遅れていますが、8 年前にかなりの作業を行いました。
ネストされた複数の名前空間を簡単かつ効率的に作成して、複雑な Web アプリケーションを整理して管理しやすくすると同時に、JavaScript グローバル名前空間を尊重し (名前空間の汚染を防ぎます)、名前空間パス内の既存のオブジェクトを破壊しないようにすることが重要です。 .
上記から、これは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);
大規模なアプリケーションでは、これを定義する必要があるのは、ページの読み込みの開始時に 1 回だけです (クライアント ベースの Web アプリの場合)。追加のファイルは、保持されている場合は名前空間関数を再利用できます (上記の「オプション」として含まれています)。最悪の場合、この関数が数回再宣言された場合、数行のコードしかなく、縮小された場合はそれ以下になります。
いくつかのライブラリを別のプロジェクトに移植し、常に最上位の(静的に名前が付けられた)名前空間を変更する必要があった後、名前空間を定義するためにこの小さな(オープンソース)ヘルパー関数を使用するように切り替えました。
global_namespace.Define('startpad.base', function(ns) {
var Other = ns.Import('startpad.other');
....
});
利点の説明は私のブログ投稿にあります。ここでソースコードを入手できます。
私が本当に気に入っている利点の1つは、ロード順序に関してモジュールを分離できることです。ロードする前に外部モジュールを参照できます。また、取得したオブジェクト参照は、コードが利用可能になったときに入力されます。
名前空間には次の構文を使用します。
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/
Jaco Pretorius のソリューションが気に入っていますが、「this」キーワードをモジュール/名前空間オブジェクトに向けることで、もう少し便利にしたかったのです。私のバージョンのスキレット:
(function ($, undefined) {
console.log(this);
}).call(window.myNamespace = window.myNamespace || {}, jQuery);
このように独立して使用できます。
var A = A|| {};
A.B = {};
A.B = {
itemOne: null,
itemTwo: null,
};
A.B.itemOne = function () {
//..
}
A.B.itemTwo = function () {
//..
}
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();
Makefile の 1 行を削除するだけで大量のコードを効果的にコメントアウトできるため、約 1000 行になったら Makefile を使用することを好みます。物をいじるのが簡単になります。また、この手法を使用すると、名前空間はプレリュードに 1 回しか表示されないため、簡単に変更でき、ライブラリ コード内で繰り返し続ける必要がありません。
makefile を使用する場合のブラウザーでのライブ開発用のシェル スクリプト:
while (true); do make; sleep 1; done
これを make タスク 'go' として追加すると、'make go' を実行して、コーディング中にビルドを最新の状態に保つことができます。
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
パッケージ/ユニットが他の言語で行うように、もう少し機能する別の名前空間ライブラリを作成しました。JavaScript コードのパッケージを作成し、他のコードからそのパッケージを参照できます。
Package("hello", [], function() {
function greeting() {
alert("Hello World!");
}
// Expose function greeting to other packages
Export("greeting", greeting);
});
Package("example", ["hello"], function(greeting) {
// Greeting is available here
greeting(); // Alerts: "Hello World!"
});
ページに含める必要があるのは 2 番目のファイルだけです。その依存関係 (この例ではhello.jsファイル) は自動的に読み込まれ、それらの依存関係からエクスポートされたオブジェクトは、コールバック関数の引数を設定するために使用されます。
関連するプロジェクトはPackages JSにあります。
私の習慣は、関数 myName()をプロパティ ストレージとして使用し、次にvar 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();