当前位置:  开发笔记 > 编程语言 > 正文

如何在JavaScript中声明命名空间?

如何解决《如何在JavaScript中声明命名空间?》经验,为你挑选了17个好方法。

如何在JavaScript中创建命名空间,以便我的对象和函数不会被其他同名的对象和函数覆盖?我用过以下内容:

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

这样做有更优雅或简洁的方式吗?



1> Jaco Pretori..:

我使用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 ));

因此,如果您想访问其中一个公共成员,您只需要去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 ));
第三个undefined论点

第三个undefined参数是值变量的来源undefined.我不确定它今天是否仍然有用,但是在使用旧的浏览器/ JavaScript标准(ecmascript 5,javascript <1.8.5~firefox 4)时,全局范围变量undefined是可写的,所以任何人都可以重写它的值.第三个参数(未传递值时)创建一个名为undefinedrange 的变量,该变量的作用域为命名空间/函数.由于在创建名称空间时未传递任何值,因此默认为该值undefined.


@CpILL:不确定是否仍然相关,但第三个`undefined`参数是值为'undefined`的变量的来源.在使用旧版浏览器/ javascript标准(ecmascript 5,javascript <1.8.5~firefox 4)时,全局范围变量`undefined`是可写的,因此任何人都可以重写其值.添加第三个,你没有传递的附加参数使它值为'undefined`,所以你创建了命名空间范围`undefined`,它不会被外部源重写.
从以利亚的文章,这里是这种方法的利弊,转述.优点:1.公共和私有属性和方法,2.不使用繁琐的OLN,3.保护未定义4.确保$引用jQuery,5.命名空间可以跨文件,缺点:比OLN更难理解
+1这个伟大的样本.对于任何有兴趣的人来说,这个样本是Elijah Manor在Mix 2011上的精彩演示的一部分(忽略标题)http://live.visitmix.com/MIX11/Sessions/Speaker/Elijah-Manor
@SapphireSun`window.skillet = window.skillet ||的好处 {}`它允许多个脚本在事先不知道它们将执行的顺序时安全地添加到同一名称空间.如果您希望能够在不破坏代码的情况下任意重新排序脚本包含,或者如果您想要使用[async属性]异步加载脚本,这可能会有所帮助(https://developer.mozilla.org/en/docs/Web/HTML/Element/script)所以不保证执行顺序.请参阅http://stackoverflow.com/questions/6439579/what-does-var-foo-foo-mean-in-javascript
这称为今天**IIFE**(_Immediately Invoked Function Expression_).谢谢你的答案+1!

2> dfa..:

我喜欢这个:

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();


重要的一点是要扩展一个根变量的宗教信仰.*一切*都必须从中流出.
@Ryan我的意思是一切都应该在`MyApp`下,例如`MyApp.Views.Profile = {}`而不是`MyApp.users = {}`和`MyViews.Profile = {}`.不一定只有两个级别的深度.
annakata:"重要的一点是要扩展一个根变量的宗教信仰." - 这是为什么?
这不会为你的代码创建一个闭包 - 调用你的其他函数会很繁琐,因为它们总是看起来像:yourNamespace.bar(); 我做了一个开源项目JUST来解决这个设计问题:http://github.com/mckoss/namespace.
@alex - 为什么应该有一个浅层的对象结构?
这种方法的语法真的困扰我.我讨厌不用分号结束行,并且在此解决方案声明顺序中很重要.我仍然认为它是完全有效的,并且在一些情况下是一个很好的解决方案.如何使用这种方法在JQUery调用上执行回调函数?
根据上面提到的代码,我可以在不使用yourNamespace的情况下调用bar内的foo函数吗?
@alex:我不能代表user406905,但我对annakata所说的解释是你应该在根命名空间下面有一个"级别"的属性和方法.换句话说,做我自己和我而不是我.我自己.所以你有尽可能浅的对象结构.当然我可能误解了这一点.
我在哪里添加原型到bar对象,例如bar.prototype.getFullAddress = function(opts){...
@ user406905:因为那时你有*两个*全局标识符,所以一切都应该存在于一个命名空间下.
@Alex,Ryan,或者只是在匿名或命名的IIFE中封装对象文字(命名空间)(尽可能多)

3> Ionuț G. Sta..:

另一种方法,我认为它比对象文字形式稍微限制一点,是这样的:

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

上面的内容非常类似于模块模式,无论您喜欢与否,它都允许您将所有功能公开,同时避免使用对象文字的严格结构.


1. OLN和模块模式之间存在差异.2.我不/永远/喜欢OLN,因为你必须记住不要输入最后一个尾随逗号,所有属性必须用值初始化(如null或undefined).此外,如果需要成员函数的闭包,那么每个方法都需要小函数工厂.另一件事是你必须将所有的控制结构都包含在函数中,而上面的表格并没有强制执行.这并不是说我不使用OLN,只是有时我不喜欢它.
@John Kraft,这是因为'function`关键字前面的`new`关键字.基本上,正在做的是它声明一个匿名函数(作为一个函数,它也是一个构造函数),然后它立即使用`new`作为构造函数调用它.因此,存储在`ns`中的最终值是该匿名构造函数的(唯一)实例.希望它有意义.
我喜欢这个比逗号更高的逗号分隔对象容器更好.相比之下,我也没有看到任何缺点.我错过了什么吗?
我喜欢这种方法,因为它允许私有函数,变量和伪常量(即var API_KEY = 12345;).
JS新手在这里...为什么我不必输入`ns().publicFunction()`,即...`ns.publicFunction()`有效.
这种模式适用于单例对象,但`jQuery`是一个构造函数.在我的例子中,你不能调用`ns()`,而jQuery需要这个.
另外值得一提的是,在上面的例子中,`this`指的是你在`publicFunction`中所期望的,但是指的是`internalFunction`中的全局对象.我通常在顶部添加`var self = this`以避免混淆.
有点瞎了我,任何人都不会喜欢OLN.我只是...什么不爱?什么是如此僵化?
现在,如果JSLint不会抱怨这个合法的结构,一切都会好得多:)
使用这种方法的类型:如果您想在"内部"方法中访问"公共"成员或方法,则必须添加"类"名称.示例:ns.publicFunction(); 或ns.publicMember;

4> Alex Pacurar..:

这样做有更优雅或简洁的方式吗?

是.例如:

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 your_namespace = your_namespace = your_namespace || {}适用于每个浏览器;)
您可以在不同的js文件中扩展your_namespace对象.使用var your_namespace = {}时,您无法执行此操作,因为每个文件都会覆盖该对象
@Palo你能解释为什么会这样吗?`var your_namespace = your_namespace = your_namespace || {}`

5> Brett Ryan..:

我通常在一个闭包中构建它:

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语句视为实现的公共接口.


你不应该检查`MYNS.subns = MYNS.subns || {}`??
优化提示:虽然`var foo = function`和`function foo`是相似的,是私有的; 由于JavaScript具有动态类型的特性,后者在某些解释器的管道中跳过一些指令时会稍微快一些.随着`VAR foo`,类型系统必须被调用,以找出哪些类型被分配到说的VAR,同时用`函数foo`,类型系统自动知道它是一个函数,所以一对夫妇函数调用get跳过,这转换为更少的CPU指令调用,如`jmp`,`pushq`,`popq`等,转换为更短的CPU管道.

6> 小智..:

因为您可以编写不同的JavaScript文件,然后在应用程序中组合或不组合它们,每个文件都需要能够恢复或构造命名空间对象而不会损坏其他文件的工作...

一个文件可能打算使用命名空间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(){}

这两个文件可以在一起或分开存在而不会发生冲突.



7> Ciaran Bruen..:

以下是Stoyan Stefanov如何在他的JavaScript Patterns书中做到这一点,我发现它非常好(它还展示了他如何做出允许自动生成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;
};



8> AnthonyWJone..:

我用这种方法:

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


@paul:"更好"可能非常主观.我讨厌阅读SHOUTS给我的代码,所以我避免使用全部使用大写的标识符.同时`ns = ns || {}`可能看起来更具防御性,可能导致其他意外结果.

9> Rudy Lattae..:

这是user106826指向Namespace.js的链接的后续内容.该项目似乎转移到了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文件.


只要你记得这有一些性能影响,每次你访问my.awesome.package.WildClass时,你都会访问我的awesome属性,my.awesome的package属性和my.awesome的WildClass属性.包.

10> Jim Jose..:

样品:

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变量,sameself和分配local.onTimeout,如果你希望它是私有的.



11> 小智..:

您可以声明一个简单的函数来提供名称空间.

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



12> Tadej..:

如果您需要私人范围:

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



13> Divyanshu Ra..:

模块模式最初被定义为为传统软件工程中的类提供私有和公共封装的方法.

使用Module模式时,我们可能会发现定义一个我们用于开始使用它的简单模板很有用.这是一个涵盖名称间距,公共和私有变量的.

在JavaScript中,Module模式用于进一步模拟类的概念,使得我们能够在单个对象中包含公共/私有方法和变量,从而将特定部分与全局范围隔离开来.这导致我们的函数名称与页面上其他脚本中定义的其他函数冲突的可能性降低.

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

    }
  };

})();

好处

为什么Module模式是个不错的选择?对于初学者来说,对于来自面向对象背景的开发人员来说,比真正封装的想法更加清晰,至少从JavaScript的角度来看.

其次,它支持私有数据 - 因此,在模块模式中,代码的公共部分能够触及私有部分,但外部世界无法触及类的私有部分.

缺点

Module模式的缺点是,当我们以不同方式访问公共成员和私有成员时,当我们希望更改可见性时,我们实际上必须对使用该成员的每个位置进行更改.

我们也无法在以后添加到对象的方法中访问私有成员.也就是说,在许多情况下,模块模式仍然非常有用,如果使用得当,肯定有可能改善我们的应用程序结构.

揭示模块模式

现在我们对模块模式稍微熟悉一下,让我们看一下稍微改进的版本 - Christian Heilmann的Revealing Module模式.

揭示模块模式的出现是因为Heilmann对于当我们想要从另一个公共方法调用一个公共方法或访问公共变量时必须重复主对象的名称这一事实感到沮丧.他也不喜欢Module模式的必须切换的要求对他希望公开的事物反对文字符号.

他努力的结果是一个更新的模式,我们将简单地定义私有范围中的所有函数和变量,并返回一个匿名对象,其中包含指向我们希望公开的私有功能的指针.

下面是一个如何使用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" );

好处

此模式允许脚本的语法更加一致.它还使模块结尾处的内容更加清晰,我们可以公开访问哪些函数和变量,从而简化了可读性.

缺点

这种模式的缺点是,如果私有函数引用公共函数,则如果需要补丁,则不能覆盖该公共函数.这是因为私有函数将继续引用私有实现,并且该模式不适用于公共成员,仅适用于函数.

引用私有变量的公共对象成员也受上面的无补丁规则说明的约束.



14> The Who..:

我创建的命名空间受到Erlang模块的启发.这是一种非常实用的方法,但这就是我最近编写JavaScript代码的方法.

它为闭包提供了一个全局命名空间,并在该闭包中公开了一个已定义的set函数.

(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

})();



15> Razan Paul..:

我对命名空间使用以下语法.

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/



16> mckoss..:

在将我的几个库移植到不同的项目之后,并且不得不经常更改顶级(静态命名)命名空间之后,我转而使用这个小的(开源)辅助函数来定义命名空间.

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

这些好处的描述在我的博客文章中.您可以在此处获取源代码.

我真正喜欢的一个好处是模块之间的负载顺序隔离.您可以在加载外部模块之前参考它.当代码可用时,您将获得对象引用.



17> ziesemer..:

我参加晚会已经晚了7年,但是在8年前做了相当多的工作:

http://blogger.ziesemer.com/2008/05/javascript-namespace-function.html

http://blogger.ziesemer.com/2007/10/respecting-javascript-global-namespace.html

重要的是能够轻松高效地创建多个嵌套命名空间,以保持复杂的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

使用示例:

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

或者,作为一个声明:

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);
推荐阅读
女女的家_747
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有