如何在JavaScript中声明名称空间?
如何在JavaScript中创建名称空间,以便我的对象和函数不会被其他同名对象和函数覆盖?我使用了以下方法:如何在JavaScript中声明名称空间?,javascript,namespaces,javascript-namespaces,Javascript,Namespaces,Javascript Namespaces,如何在JavaScript中创建名称空间,以便我的对象和函数不会被其他同名对象和函数覆盖?我使用了以下方法: if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();} $OHU.initialization = function(){ //Your Code Here }; 有没有更优雅或简洁的方法呢?我喜欢这样: var yourNamespace = { foo: function()
if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}
$OHU.initialization = function(){
//Your Code Here
};
有没有更优雅或简洁的方法呢?我喜欢这样:
var yourNamespace = {
foo: function() {
},
bar: function() {
}
};
...
yourNamespace.foo();
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
};
})();
我使用这种方法:
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);
另一种方法,我认为它比对象文字形式稍微有点限制,是:
var ns = new function() {
var internalFunction = function() {
};
this.publicFunction = function() {
};
};
上面的内容非常类似,它允许您将所有函数公开为公共函数,同时避免对象文字的僵化结构。将我的几个库移植到不同的项目后,必须不断更改顶级静态命名名称空间,我已经转而使用这个小型的开源助手函数来定义名称空间
global_namespace.Define('startpad.base', function(ns) {
var Other = ns.Import('startpad.other');
....
});
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!";
福利的描述在我的网站上。你可以拿着这个
我真正喜欢的好处之一是模块之间在加载顺序方面的隔离。您可以在加载外部模块之前引用它。当代码可用时,将填写您获得的对象引用
有没有更优雅或简洁的方法
对。例如:
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);
}
我创建了一个以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
})();
这是user106826到Namespace.js链接的后续内容。看来这个项目已经开始了。现在是 我一直在为我的小项目使用这个简单的JavaScript助手,到目前为止,它似乎很轻,但功能齐全,足以处理名称空间和加载模块/类。如果它允许我将一个包导入到我选择的名称空间中,而不仅仅是全局名称空间,那就太好了。。。唉,但这不是重点 它允许您声明命名空间,然后在该命名空间中定义对象/模块:
Namespace('my.awesome.package');
my.awesome.package.WildClass = {};
另一个选项是立即声明命名空间及其内容:
Namespace('my.awesome.package', {
SuperDuperClass: {
saveTheDay: function() {
alert('You are welcome.');
}
}
});
有关更多用法示例,请查看中的example.js文件。因为您可能会编写不同的JavaScript文件,然后在应用程序中合并或不合并它们,因此每个文件都需要能够恢复或构造名称空间对象,而不会损坏其他文件的工作 一个文件可能打算使用名称空间。名称空间1: 另一个文件可能要使用名称空间。名称空间2:
这两个文件可以在一起或分开而不会发生冲突。我编写了另一个名称空间库,它的工作原理与其他语言中的包/单元类似。它允许您创建一个JavaScript代码包,并从其他代码中引用该包: 文件hello.js 文件Example.js 页面中只需包含第二个文件。本例中的依赖项文件hello.js将自动加载,从这些依赖项导出的对象将用于填充回调函数的参数
(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 ));
namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);
您可以在中找到相关项目。如果使用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中的一行有效地注释掉大量代码。它使摆弄东西变得容易。此外,使用这种技术,名称空间在前奏曲中只出现一次,因此很容易更改,并且不必在库代码中重复它
使用生成文件时,浏览器中用于实时开发的shell脚本:
while (true); do make; sleep 1; done
将此添加为make任务“go”,您可以在编写代码时“make go”以保持构建的更新。我使用:
下面是他们的示例,展示了如何声明私有和公共属性和函数。一切都是作为一个自动执行的匿名函数完成的
(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 ));
namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);
因此,如果你想访问其中一个公共成员,你只需使用skillet.fry或skillet.配料
真正酷的是,现在可以使用完全相同的语法扩展名称空间
//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 ));
第三个未定义的参数
第三个未定义参数是未定义值变量的来源。我不确定它在今天是否仍然适用,但在使用旧浏览器/JavaScript标准ecmascript 5、JavaScript<1.8.5~ firefox 4时,全局范围变量undefined是可写的,因此任何人都可以重写它的值。第三个参数在未传递值时创建一个名为undefined的变量,该变量的作用域为命名空间/函数。由于创建名称空间时未传递任何值,因此默认为未定义的值
我通常在闭包中构建它:
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 yourNamespace = {
foo: function() {
},
bar: function() {
}
};
...
yourNamespace.foo();
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和实现更容易理解。想一想re
将语句转换为实现的公共接口。以下是Stoyan Stefanov在他的书中的做法,我发现这本书非常好。它还显示了他如何进行注释,允许自动生成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;
};
您可以声明一个简单的函数来提供名称空间
global_namespace.Define('startpad.base', function(ns) {
var Other = ns.Import('startpad.other');
....
});
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!";
样本:
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;
})()
如果希望局部变量是私有的,您可以选择声明一个相同的局部变量,如self和assign local.onTimeout。我喜欢Jaco Pretorius的解决方案,但我希望通过将this关键字指向模块/名称空间对象,使其更有用。 我的煎锅版本:
(function ($, undefined) {
console.log(this);
}).call(window.myNamespace = window.myNamespace || {}, jQuery);
我对名称空间使用以下语法
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());
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()
JSIDLE:我的习惯是使用函数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!')
);
如果这个!==myObj.fName1;else-myObj.fName2
您还可以通过“反之亦然”的方式在创建对象之前进行检查,这样做会更好:
参考:这是IonuțG.Stan答案的后续,但通过使用var ClassFirst=this.ClassFirst=function{…}显示了整洁代码的好处,它利用JavaScript的闭包作用域减少了相同命名空间中类的命名空间混乱
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());
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
我们可以这样独立使用它:
var A = A|| {};
A.B = {};
A.B = {
itemOne: null,
itemTwo: null,
};
A.B.itemOne = function () {
//..
}
A.B.itemTwo = function () {
//..
}
我最喜欢的模式最近变成了: var namespace=函数{ //曝光 返回{ a:a, c:internalC } //都是私人的 /** *完整JSDoc */ 内部功能{ // ... } /** *完整JSDoc */ 内部功能B{ // ... } /** *完整JSDoc */ 内部功能{ // ... } /** *完整JSDoc */ 内在功能{ // ... }
}; 在JavaScript中,没有使用名称空间的预定义方法。在JavaScript中,我们必须创建自己的方法来定义名称空间。以下是我们在Oodles technologies中遵循的程序 注册名称空间 下面是注册名称空间的函数
//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]];
}
}
基本上,它将在后端创建名称空间结构,如下所示:
var oodles = {
"HomeUtilities": {},
"GlobalUtilities": {}
};
在上面的函数中,您注册了一个名为oodles.HomeUtilities和oodles.GlobalUtilities的命名空间。为了调用这些名称空间,我们创建了一个变量,即var$OHU和var$OGU
这些变量只是初始化名称空间的别名。
现在,每当您声明一个属于HomeUtilities的函数时,您都会像下面那样声明它:
if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}
$OHU.initialization = function(){
//Your Code Here
};
上面是函数名初始化,它被放入一个名称空间$OHU中。并在脚本文件中的任何位置调用此函数。只需使用以下代码
$OHU.initialization();
类似地,使用另一个名称空间
希望能有所帮助。我参加聚会晚了7年,但8年前我做了很多工作: 能够轻松高效地创建多个嵌套名称空间以保持复杂web应用程序的组织性和可管理性,同时尊重JavaScript全局名称空间以防止名称空间污染,并且在这样做时不碰撞名称空间路径中的任何现有对象,这一点很重要 综上所述,这是我的circa-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;
};
或者,作为一种说法:
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;
};
现在,我对将名称空间暴露于全局名称空间本身持谨慎态度。太糟糕了,基础语言没有为我们提供这一点!因此,我通常会在结束语中使用这一点,例如:
作用{
const namespace=函数名、分隔符、容器{
var o=容器| |窗口;
name.splitseparator | |'。.forEachfunctionx{
o=o[x]=o[x]|{};
};
返回o;
};
const ns=namespacecom.ziesemer.myApp;
//可选:
ns.namespace=ns;
//进一步扩展,从这里开始与ns合作。。。
};
console.log\com\:,com 模块模式最初定义为在传统软件工程中为类提供私有和公共封装的一种方式 在使用模块模式时,我们可能会发现定义一个简单的模板非常有用,我们可以使用该模板开始使用它。这里有一个涵盖了名称间距、公共变量和私有变量 在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的启示模块模式
当我们想从另一个公共方法调用一个公共方法或访问公共变量时,Heilmann不得不重复主要对象的名称,这一事实让Heilmann感到沮丧。他也不喜欢模块模式要求必须为他想做的事情切换到对象文字符号公众
他的努力的结果是一个更新的模式,我们只需在私有范围内定义所有函数和变量,并返回一个匿名对象,其中包含指向我们希望公开的私有功能的指针
下面是如何使用显示模块模式的示例
优势
这种模式允许脚本的语法更加一致。在模块结束时,它还使我们更加清楚哪些函数和变量可以公开访问,从而简化了可读性
缺点
这种模式的一个缺点是,如果私有函数引用公共函数,则如果需要修补程序,则不能重写该公共函数。这是因为私有函数将继续引用私有实现,并且该模式不适用于公共成员,只适用于函数
引用私有变量的公共对象成员也受上述无补丁规则注释的约束。如果需要私有范围:
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();
否则,如果您永远不会使用私有作用域:
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();
我认为对于这样一个简单的问题,你们都使用了太多的代码。 没有必要为此进行回购。 这是一个单行函数
(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 ));
namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);
试试看:
//-定义--
const namespace=name=>name.split..reducelast=>last[next]=last[next]| |{},窗口;
//-使用--
常数c=名称空间a.b.c;
c、 MyClass=类MyClass{};
//-看--
console.loga:,a 默认情况下,JavaScript不支持命名空间。因此,如果创建任何elementfunction、方法、对象、变量,那么它将成为全局的,并污染全局命名空间。让我们以定义两个没有名称空间的函数为例
function func1() {
console.log("This is a first definition");
}
function func1() {
console.log("This is a second definition");
}
func1(); // This is a second definition
它总是调用第二个函数定义。在这种情况下,名称空间将解决名称冲突问题。我可以看到检查名称空间是否被占用的步骤,但由于如果失败,将不会创建对象,因此我认为更好的方法是在使用名称空间时发出警报。坦白地说,这在大多数JS情况下都不应该发生,并且应该在开发过程中迅速发现。拥有它。应在测试的早期检测冲突。不要费心添加所有这些假设检查。对于重复的名称空间来说,这是一个致命的问题,应该这样对待。您可以使用jQuery这样的方法来允许驻留自定义名称空间;但这仍然是设计时的问题。另请参见性能问题也请参见对象与函数名称空间这是大量的信息,但实际上列出了不同JS设计模式之间的差异。这给了我很大帮助:重要的一点是,不要再扩展一个根变量了。一切都必须从这里开始。这不会为你的代码创建一个闭包——它会让调用其他函数变得单调乏味,因为它们总是看起来像:yourNamespace.bar;我做了一个开源项目就是为了解决这个设计问题:。安娜卡塔:重要的一点是不要扩展超过一个根变量。-为什么会这样?@alex-为什么应该有一个浅层对象结构?@Ryan我的意思是所有东西都应该在MyApp下,例如MyApp.Views.Profile={}而不是MyApp.users={}和MyViews.Profile={}。不一定只有两级深度。1.OLN和模块模式之间有区别。2.我不/总是/喜欢OLN,因为你必须记住不要放最后一个尾随逗号,所有属性都必须用null或undefined之类的值初始化。此外,如果你需要成员函数的闭包,那么
每种方法都需要小型函数工厂。另一件事是,您必须将所有的控制结构封装在函数中,而上面的表单并没有强制要求这样做。这并不是说我不使用OLN,只是有时候我不喜欢它。我喜欢这种方法,因为它允许使用私有函数、变量和伪常量,即var API_KEY=12345;。我喜欢这个比逗号分隔的对象容器更高。相比之下,我也没有发现任何缺点。我错过什么了吗?这里是JS新手。。。为什么我不必键入ns.publicFunction,即。。。ns.publicFunction有效。@约翰·卡夫,这是因为function关键字前面有一个新关键字。基本上,它所做的是声明一个匿名函数,作为一个函数,它也是一个构造函数,然后它立即使用new作为构造函数调用它。因此,存储在ns中的最终值是该匿名构造函数的唯一实例。希望它有意义。我已经创建了名称空间库的改进版2.0:您的所有链接看起来都非常详细!谢谢只是想知道你对Namespace.js的看法。我从来没有用过它,所以我想知道如果有人有你的知识/技能/经验会考虑使用它。我喜欢它!另一方面,我在这个外部代码的第一行得到了异常,它说:“myNameSpace.MyClass”[undefined]不是构造函数。也许这取决于JS实现/@约西巴:可能吧。上面的代码是相当标准的东西。在标准JS中,任何函数都可以用作构造函数,无需将函数标记为专门用作构造函数。您使用的是ActionScript之类的特殊风格吗?@Anthony最好使用var MYNAMESPACE=MYNAMESPACE | |{};仅仅使用var myNamespace={}是不安全的,而且最好在caps@paul:更好可能是相当主观的。我讨厌读那个些冲我吼叫的代码,所以我避免使用全大写的标识符。虽然ns=ns |{}看起来更具防御性,但它可能会导致其他意外的结果。var your_namespace=typeof your_namespace==undefined | |!你的名字空间?{}:您的_名称空间;效果更好。你的_namespace=你的_namespace=你的| |{}在每个浏览器中都能工作+从我这里得到1分!Thin one通过将一个库扩展到不同的文件或同一文件中的不同位置来充当Jaco Pretorius answer。太棒了@帕洛你能解释一下为什么会这样吗?var your_namespace=your_namespace=your|namespace |{}您可以在不同的js文件中扩展your_namespace对象。当使用var your_namespace={}时,您不能这样做,因为对于这个伟大的示例,对象将被每个文件+1覆盖。对于任何感兴趣的人来说,这个样本是Elijah Manor在2011年Mix大会上出色演讲的一部分。忽略Elijah文章的标题,这里是这种方法的优点和缺点。优点:1。公共和私有属性和方法,2。不使用笨重的OLN,3。保护未定义的4。确保$5引用jQuery。名称空间可以跨越文件,缺点是:比Ol更难理解这就是今天的IIFE立即调用函数表达式。谢谢你的回答+1@CpILL:不确定是否仍然相关,但第三个未定义参数是未定义值变量的源。在使用旧浏览器/javascript标准ecmascript 5(javascript<1.8.5~firefox 4)时,全局作用域变量undefined是可写的,因此任何人都可以重写其值。添加第三个未传递的附加参数会使其值未定义,因此您创建的命名空间范围未定义,不会被外部源重写。@SapphireSun window.skillet=window.skillet | |{它允许多个脚本在事先不知道执行顺序时安全地添加到同一名称空间。如果您希望能够在不中断代码的情况下对脚本包含进行任意重新排序,或者希望异步加载脚本,因此无法保证执行顺序,那么这将非常有用。请注意,只要您还记得,这会对性能产生一些影响,因为每次访问my.awesome.package.WildClass时,您都在访问my的awesome属性、my.awesome的package属性和my.awesome.package.WildClass属性。您是否应该检查MYNS.subns=MYNS.subns | |{??这是一个很好的观点,应该是对开发人员意图的练习。您需要考虑当它存在时应该做什么,替换它,错误,使用现有的或版本检查并有条件地替换。我遇到过不同的情况,每种情况都需要不同的变体。在大多数情况下,你可能将此作为一个低风险的边缘情况,替换可能是有益的,考虑一个试图劫持N的流氓模块。
在第412页的《说Javascript》一书中,在标题为“快速和肮脏的模块”下有对这种方法的解释;由于JavaScript的动态类型特性,后者稍微快一些,因为它跳过了大多数解释器管道中的一些指令。使用var foo,类型系统必须被调用以找出分配给所述var的类型,而使用function foo,类型系统自动知道它是一个函数,因此跳过了几个函数调用,从而减少了对CPU指令(如jmp、pushq、popq等)的调用,这将转换为更短的CPU管道。@brett-oops。你说得对。我在考虑另一种脚本语言。尽管我仍然坚持函数foo语法更具可读性。我仍然喜欢我的版本。@peter mortensen对我11年的答案进行编辑真的有必要吗?你所做的绝对不是故意破坏,别误会我的意思,但它们很肤浅。除非你真的添加了一些好东西,否则我更愿意成为此类帖子的唯一作者。我发现这是一种非常有用的方法,可以在功能需要模块化的大型应用程序中将客户端脚本组织到多个文件中。专门针对多个文件提出的问题:您好,如何从代码片段中调用公共函数?我试过名称空间@奥利弗:是的,就是这个主意。虽然现在使用ES6,但我通常使用对象文本的速记语法,我只想强调函数定义末尾的集合。它们是必需的,很容易错过它们。我遇到了与@olimart相同的问题,并通过添加它们解决了这个问题。