如何在 JavaScript 中声明命名空间?
如何在 JavaScript 中创建命名空间,以便我的对象和函数不会被其他同名对象和函数覆盖? 我使用了以下内容:
if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}
是否有更优雅或更简洁的方法来执行此操作?
How do I create a namespace in JavaScript so that my objects and functions aren't overwritten by other same-named objects and functions? I've used the following:
if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}
Is there a more elegant or succinct way of doing this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(29)
我使用 在 Enterprise jQuery 站点上找到的方法:
这是他们的示例,展示了如何声明私有和私有。 公共属性和功能。 一切都是作为自动执行的匿名函数完成的。
因此,如果您想访问公共成员之一,只需使用
skillet.fry()
或skillet.ingredients
即可。真正酷的是,您现在可以使用完全相同的语法来扩展命名空间。
第三个
未定义
参数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.
So if you want to access one of the public members you would just go
skillet.fry()
orskillet.ingredients
.What's really cool is that you can now extend the namespace using the exact same syntax.
The third
undefined
argument我喜欢这个:
I like this:
另一种方法是这样的,我认为它比对象字面量形式的限制要少一些:
上面的内容非常像 模块模式 和 无论您是否喜欢,它都允许您将所有函数公开为公共函数,同时避免对象字面量的严格结构。
Another way to do it, which I consider it to be a little bit less restrictive than the object literal form, is this:
The above is pretty much like the module pattern and whether you like it or not, it allows you to expose all your functions as public, while avoiding the rigid structure of an object literal.
是的。 例如:
那么你可以有
Yes. For example:
then you can have
我通常在闭包中构建它:
自从写这篇文章以来,多年来我的风格发生了微妙的变化,我现在发现自己像这样编写闭包:
通过这种方式,我发现公共 API 和实现更容易理解。 将 return 语句视为实现的公共接口。
I normally build it in a closure:
My style over the years has had a subtle change since writing this, and I now find myself writing the closure like this:
In this way I find the public API and implementation easier to understand. Think of the return statement as being a public interface to the implementation.
因为您可能编写不同的 JavaScript 文件,然后在应用程序中组合或不组合它们,所以每个文件都需要能够恢复或构造命名空间对象,而不破坏其他文件的工作...
一个文件可能打算使用命名空间 < code>namespace.namespace1:
另一个文件可能想要使用命名空间
namespace.namespace2
:这两个文件可以共存或分开而不会发生冲突。
Because you may write different files of JavaScript and later combine or not combine them in an application, each needs to be able to recover or construct the namespace object without damaging the work of other files...
One file might intend to use the namespace
namespace.namespace1
:Another file might want to use the namespace
namespace.namespace2
:These two files can live together or apart without colliding.
以下是 Stoyan Stefanov 在他的JavaScript Patterns一书中的做法,其中我发现非常好(它还展示了他如何进行允许自动生成 API 文档的注释,以及如何向自定义对象的原型添加方法):
Here's how Stoyan Stefanov does it in his JavaScript Patterns book which I found to be very good (it also shows how he does comments that allows for auto-generated API documentation, and how to add a method to a custom object's prototype):
我使用这种方法:
外部代码可以是:
I use this approach:
External code can then be:
这是 user106826 的 Namespace.js 链接的后续内容。 该项目似乎已转移到 GitHub。 现在是 smith/namespacedotjs。
我一直在我的小项目中使用这个简单的 JavaScript 帮助器,到目前为止,它似乎很轻,但功能多样,足以处理命名空间和加载模块/类。 如果它允许我将包导入到我选择的命名空间中,而不仅仅是全局命名空间,那就太好了……叹息,但这不是重点。
它允许您声明命名空间,然后在该命名空间中定义对象/模块:
另一种选择是立即声明命名空间及其内容:
有关更多用法示例,请查看 源代码。
This is a follow-up to user106826's link to Namespace.js. It seems the project moved to GitHub. It is now smith/namespacedotjs.
I have been using this simple JavaScript helper for my tiny project and so far it seems to be light yet versatile enough to handle namespacing and loading modules/classes. It would be great if it would allow me to import a package into a namespace of my choice, not just the global namespace... sigh, but that's besides the point.
It allows you to declare the namespace then define objects/modules in that namespace:
Another option is to declare the namespace and its contents at once:
For more usage examples, look at the example.js file in the source.
示例:
您可以选择声明一个
local
变量,same
,如self
并根据需要分配local.onTimeout
它是私人的。Sample:
You can optionally declare a
local
variable,same
, likeself
and assignlocal.onTimeout
if you want it to be private.模块模式最初被定义为一种为传统软件工程中的类提供私有和公共封装的方法。
使用模块模式时,我们可能会发现定义一个用于开始使用它的简单模板很有用。 这是一个涵盖名称空间、公共和私有变量的内容。
在 JavaScript 中,模块模式用于进一步模拟类的概念,以便我们能够在单个对象中包含公共/私有方法和变量,从而将特定部分屏蔽在全局范围之外。 这会减少我们的函数名称与页面上其他脚本中定义的其他函数发生冲突的可能性。
优点
为什么模块模式是一个不错的选择? 对于初学者来说,对于来自面向对象背景的开发人员来说,它比真正的封装的想法要干净得多,至少从 JavaScript 的角度来看是这样。
其次,它支持私有数据 - 因此,在模块模式中,我们代码的公共部分能够触及私有部分,但是外界无法触及类的私有部分。
缺点
模块模式的缺点是,由于我们以不同的方式访问公共和私有成员,因此当我们希望更改可见性时,我们实际上必须对使用该成员的每个位置进行更改。
我们也无法在稍后添加到对象的方法中访问私有成员。 也就是说,在许多情况下,模块模式仍然非常有用,并且如果正确使用,肯定有可能改进我们应用程序的结构。
显示模块模式
现在我们对模块模式有了一些了解,让我们看一下稍微改进的版本 - Christian Heilmann 的显示模块模式。
揭示模块模式的出现是因为当我们想要从另一个公共方法调用一个公共方法或访问公共变量时,Heilmann 对他必须重复主对象的名称感到沮丧。他也不喜欢模块模式必须切换的要求反对他希望公开的事物的字面符号。
他的努力结果是一种更新的模式,我们只需在私有范围中定义所有函数和变量,并返回一个匿名对象,其中包含指向我们希望公开的私有功能的指针。
如何使用揭示模块模式的示例如下
优点
此模式使我们的脚本的语法更加一致。 它还使得在模块末尾更加清楚我们的哪些函数和变量可以公开访问,从而简化了可读性。
缺点
此模式的缺点是,如果私有函数引用公共函数,则在需要修补程序时无法覆盖该公共函数。 这是因为私有函数将继续引用私有实现,并且该模式不适用于公共成员,仅适用于函数。
引用私有变量的公共对象成员也受上述无补丁规则注释的约束。
The Module pattern was originally defined as a way to provide both private and public encapsulation for classes in conventional software engineering.
When working with the Module pattern, we may find it useful to define a simple template that we use for getting started with it. Here's one that covers name-spacing, public and private variables.
In JavaScript, the Module pattern is used to further emulate the concept of classes in such a way that we're able to include both public/private methods and variables inside a single object, thus shielding particular parts from the global scope. What this results in is a reduction in the likelihood of our function names conflicting with other functions defined in additional scripts on the page.
Advantages
why is the Module pattern a good choice? For starters, it's a lot cleaner for developers coming from an object-oriented background than the idea of true encapsulation, at least from a JavaScript perspective.
Secondly, it supports private data - so, in the Module pattern, public parts of our code are able to touch the private parts, however the outside world is unable to touch the class's private parts.
Disadvantages
The disadvantages of the Module pattern are that as we access both public and private members differently, when we wish to change visibility, we actually have to make changes to each place the member was used.
We also can't access private members in methods that are added to the object at a later point. That said, in many cases the Module pattern is still quite useful and when used correctly, certainly has the potential to improve the structure of our application.
The Revealing Module Pattern
Now that we're a little more familiar with the module pattern, let’s take a look at a slightly improved version - Christian Heilmann’s Revealing Module pattern.
The Revealing Module pattern came about as Heilmann was frustrated with the fact that he had to repeat the name of the main object when we wanted to call one public method from another or access public variables.He also disliked the Module pattern’s requirement for having to switch to object literal notation for the things he wished to make public.
The result of his efforts was an updated pattern where we would simply define all of our functions and variables in the private scope and return an anonymous object with pointers to the private functionality we wished to reveal as public.
An example of how to use the Revealing Module pattern can be found below
Advantages
This pattern allows the syntax of our scripts to be more consistent. It also makes it more clear at the end of the module which of our functions and variables may be accessed publicly which eases readability.
Disadvantages
A disadvantage of this pattern is that if a private function refers to a public function, that public function can't be overridden if a patch is necessary. This is because the private function will continue to refer to the private implementation and the pattern doesn't apply to public members, only to functions.
Public object members which refer to private variables are also subject to the no-patch rule notes above.
如果您需要私有范围:
否则如果您永远不会使用私有范围:
If you need the private scope:
else if you won't ever use the private scope:
您可以声明一个简单的函数来提供名称空间。
You can declare a simple function to provide namespaces.
我迟到了 7 年,但 8 年前为此做了很多工作:
能够轻松高效地创建多个嵌套命名空间,以保持复杂的 Web 应用程序的组织性和可管理性,同时尊重 JavaScript 全局命名空间(防止命名空间污染),并且在执行此操作时不会破坏命名空间路径中的任何现有对象。
从上面来看,这是我在 2008 年左右的解决方案:
这不是创建名称空间,而是提供创建名称空间的函数。
这可以压缩为精简的一行:
使用示例:
或者,作为一个语句:
然后执行为:
如果您不需要旧版浏览器的支持,则更新版本:
现在,我会持怀疑态度将
命名空间
暴露给全局命名空间本身。 (太糟糕了,基础语言没有为我们提供这个!)所以我通常会在闭包中使用它,例如:在较大的应用程序中,只需在页面加载开始时定义一次(对于基于客户端的 Web 应用程序)。 如果保留的话,其他文件可以重用命名空间函数(在上面作为“可选”包含在内)。 最坏的情况是,如果这个函数被重新声明几次,那么它就只有几行代码,如果缩小的话,代码就会更少。
I'm 7 years late to the party, but did quite a bit of work around this 8 years ago:
It is important to be able to easily and efficiently create multiple nested namespaces to keep a complex web application organized and manageable, while respecting the JavaScript global namespace (preventing namespace pollution), and with not clobbering any existing objects in the namespace path while doing so.
From the above, this was my circa-2008 solution:
This isn't creating a namespace, but provides a function for creating namespaces.
This can be condensed to a minified one-liner:
Example of use:
Or, as one statement:
Either is then executed as:
If you don't need support for legacy browsers, an updated version:
Now, I'd be leery of exposing
namespace
to the global namespace itself. (Too bad the base language doesn't provide this for us!) So I'd typically use this myself in a closure, such as:In a larger application, this only needs to be defined once at the beginning of a page load (for client-based web apps). Additional files can then reuse the namespace function if kept (included as "optional" in the above). At worst, if this function is re-declared a few times - it's only a few lines of code, and less if minified.
我创建了命名空间,它的灵感来自于 Erlang 的模块。 这是一种非常实用的方法,但这就是我最近编写 JavaScript 代码的方式。
它为闭包提供了一个全局命名空间,并公开了该闭包中定义的集合函数。
I created namespace which is inspired by Erlang's modules. It is a very functional approach, but that is how I write my JavaScript code these days.
It gives a closure a global namespace and exposes a defined set functions within that closure.
将我的几个库移植到不同的项目,并且必须不断更改顶级(静态命名)命名空间后,我转而使用这个小型(开源)辅助函数来定义命名空间。
有关好处的描述请参见我的博客文章。 您可以此处获取源代码。
我真正喜欢的好处之一是模块之间在加载顺序方面的隔离。 您可以在加载外部模块之前对其进行引用。 当代码可用时,您获得的对象引用将被填充。
After porting several of my libraries to different projects, and having to constantly be changing the top level (statically named) namespace, I've switched to using this small (open source) helper function for defining namespaces.
Description of the benefits are at my blog post. You can grab the source code here.
One of the benefits I really like is isolation between modules with respect to load order. You can refer to an external module BEFORE it is loaded. And the object reference you get will be filled in when the code is available.
我对命名空间使用以下语法。
jsfiddle:http://jsfiddle.net/rpaul/4dngxwb3/1/
I use the following syntax for the namespace.
jsfiddle: http://jsfiddle.net/rpaul/4dngxwb3/1/
我认为你们对于这样一个简单的问题都使用了太多的代码。
无需为此创建回购协议。
这是一个单行函数。
尝试一下 :
I think you all use too much code for such a simple problem.
No need to make a repo for that.
Here's a single line function.
Try it :
ES6 模块命名空间导入
这会获取所有导出在circle.js中可用的内容,并使它们作为对象Circle的成员可用,从而有效地为其提供了自己的命名空间。
ES6 Modules Namespace imports
This grabs all the exports available inside circle.js, and makes them available as members of an object
Circle
, effectively giving it its own namespace.我最喜欢的模式最近变成了这样:
当然,return 可以放在最后,但如果后面只有函数声明,就更容易看出命名空间的全部内容以及公开的 API。
在这种情况下使用函数表达式的模式会导致在不检查整个代码的情况下无法知道公开了哪些方法。
My favorite pattern has become lately this:
Of course, return can be at the end, but if only function declarations follow it, it's much easier to see what's the namespace all about, and what API is exposed.
The pattern of using function expressions in such cases results in not being able to know what methods are exposed without going over the entire code.
我喜欢 Jaco Pretorius 的解决方案,但我想通过将“this”关键字指向模块/命名空间对象来使其更有用。
我的煎锅版本:
I like Jaco Pretorius' solution, but I wanted to make the "this" keyword a bit more useful by pointing it to the module/namespace object.
My version of skillet:
JavaScript 还没有命名空间的本机表示,但 TypeScript 有。
例如,您可以使用以下 TS 代码 (
如果可以的话”如果你不更新你的代码到 TS,你至少可以使用 TS 在为命名空间生成 JS 输出时使用的模式,如下所示:
进一步阅读:
JavaScript does not yet have a native representation of namespaces, but TypeScript does.
For example, you could use the following TS code (playground)
If you can't update your code to TS, you can at least use the pattern employed by TS when generating the JS output for namespaces, which looks like this:
Further Reading:
如果使用 Makefile,您可以执行此操作。
无论如何,一旦达到大约 1000 行,我更喜欢使用 Makefile,因为我可以通过删除 makefile 中的一行来有效地注释掉大段代码。 它使得摆弄东西变得很容易。 此外,使用这种技术,名称空间仅在前奏中出现一次,因此很容易更改,并且您不必在库代码中不断重复它。
使用 makefile 时在浏览器中进行实时开发的 shell 脚本:
将其添加为 make 任务“go”,您可以“make go”以在编码时保持构建更新。
If using a Makefile you can do this.
I prefer to use a Makefile anyway once I get to about 1000 lines because I can effectively comment out large swaths of code by removing a single line in the makefile. It makes it easy to fiddle with stuff. Also, with this technique the namespace only appears once in the prelude so it's easy to change and you don't have to keep repeating it inside the library code.
A shell script for live development in the browser when using a makefile:
Add this as a make task 'go' and you can 'make go' to keep your build updated as you code.
这是 Ionuş G. Stan 答案的后续,但通过使用
var ClassFirst = this.ClassFirst = function() {...}
展示了整洁代码的好处,它利用了 JavaScript 的闭包减少同一命名空间中的类的命名空间混乱。输出:
Quite a follow-up of Ionuț G. Stan's answer, but showing the benefits of uncluttered code by using
var ClassFirst = this.ClassFirst = function() {...}
, which takes advantage of JavaScript's closure scoping for less namespace cluttering for classes in the same namespace.Output:
我编写了另一个命名空间库,其工作方式更像其他语言中的包/单元。 它允许您创建 JavaScript 代码包以及来自其他代码的包的引用:
文件 hello.js
文件 Example.js
仅第二个文件需要包含在页面中。 它的依赖项(本例中的文件hello.js)将自动加载,并且从这些依赖项导出的对象将用于填充回调函数的参数。
您可以在Packages JS中找到相关项目。
I've written another namespacing library that works a bit more like packages / units do in other languages. It allows you to create a package of JavaScript code and the reference that package from other code:
File hello.js
File Example.js
Only the second file needs to be included in the page. Its dependencies (file hello.js in this example) will automatically be loaded and the objects exported from those dependencies will be used to populate the arguments of the callback function.
You can find the related project in Packages JS.
我们可以这样独立使用:
We can use it independently in this way:
在 JavaScript 中,没有预定义的方法来使用命名空间。 在 JavaScript 中,我们必须创建自己的方法来定义名称空间。 这是我们在 Ooodles 技术中遵循的过程。
注册命名空间
以下是注册命名空间的函数
要注册命名空间,只需调用上述函数,并将参数作为命名空间,以
'.'
(点)分隔。例如
让你的应用程序名称是oodles。 您可以通过以下方法创建命名空间
基本上,它将在后端创建如下所示的 NameSpaces 结构:
在上面的函数中,您注册了一个名为
"oodles.HomeUtilities"
和"oodles.GlobalUtilities" 的命名空间“
。 为了调用这些命名空间,我们创建一个变量,即 var$OHU
和 var$OGU
。这些变量只不过是初始化命名空间的别名。
现在,每当您声明一个属于
HomeUtilities
的函数时,您将按如下方式声明它:上面是函数名称初始化,并将其放入命名空间
$OHU
中。 并在脚本文件中的任何位置调用此函数。 只需使用以下代码即可。类似地,还有另一个命名空间。
希望能帮助到你。
In JavaScript there are no predefined methods to use namespaces. In JavaScript we have to create our own methods to define NameSpaces. Here is a procedure we follow in Oodles technologies.
Register a NameSpace
Following is the function to register a name space
To register a Namespace just call the above function with the argument as name space separated by
'.'
(dot).For Example
Let your application name is oodles. You can make a namespace by following method
Basically it will create your NameSpaces structure like below in backend:
In the above function you have register a namespace called
"oodles.HomeUtilities"
and"oodles.GlobalUtilities"
. To call these namespaces we make an variable i.e. var$OHU
and var$OGU
.These variables are nothing but an alias to Intializing the namespace.
Now, Whenever you declare a function that belong to
HomeUtilities
you will declare it like following:Above is the function name initialization and it is put into an namespace
$OHU
. and to call this function anywhere in the script files. Just use following code.Similarly, with the another NameSpaces.
Hope it helps.
我的习惯是使用function myName()作为属性存储,然后var myName作为“方法”持有者......
无论这是否足够合法,打败我! 我一直依赖我的 PHP 逻辑,一切都很顺利。 :D
if (this !== that) myObj.fName1(); 否则 myObj.fName2();
参考此:JavaScript:使用 Object.create() 创建对象
My habit is to use function myName() as property storage, and then var myName as "method" holder...
Whether this is legitimate enough or not, beat me! I am relying on my PHP logic all the time, and things simply work. :D
if (this !== that) myObj.fName1(); else myObj.fName2();
Reference to this: JavaScript: Creating Object with Object.create()
JavaScript 默认不支持命名空间。 因此,如果您创建任何元素(函数、方法、对象、变量),那么它就会成为全局元素并污染全局命名空间。 让我们以定义两个没有任何命名空间的函数为例,
它总是调用第二个函数定义。 在这种情况下,命名空间将解决名称冲突问题。
JavaScript doesn’t support namespace by default. So if you create any element(function, method, object, variable) then it becomes global and pollute the global namespace. Let's take an example of defining two functions without any namespace,
It always calls the second function definition. In this case, namespace will solve the name collision problem.