如何在JavaScript中创建命名空间,使我的对象和函数不被其他同名对象和函数覆盖?我使用了以下方法:

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

有没有更优雅或更简洁的方式来做到这一点?


当前回答

在JavaScript中,没有预定义的方法来使用名称空间。在JavaScript中,我们必须创建自己的方法来定义NameSpaces。下面是我们在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;

基本上,它会在后端创建你的命名空间结构,如下所示:

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

在上面的函数中,您注册了一个名为“oodles”的命名空间。homeuutilities”和“oodles.GlobalUtilities”。为了调用这些命名空间,我们创建了一个变量,即var $OHU和var $OGU。

这些变量只是初始化名称空间的别名。 现在,当你声明一个属于HomeUtilities的函数时,你会像这样声明它:

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

上面是函数名初始化,并将其放入命名空间$OHU中。并在脚本文件中的任何地方调用此函数。只需使用下面的代码。

$OHU.initialization();

类似地,对于另一个NameSpaces。

希望能有所帮助。

其他回答

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

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

    }
  };

})();

优势

为什么模块模式是一个很好的选择?首先,对于来自面向对象背景的开发人员来说,它比真正的封装思想要简洁得多,至少从JavaScript的角度来看是这样。

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

缺点

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

我们也不能访问稍后添加到对象的方法中的私有成员。也就是说,在许多情况下,模块模式仍然是非常有用的,如果使用正确,肯定有潜力改善我们的应用程序的结构。

揭示模块模式

现在我们对模块模式有了一些熟悉,让我们来看看稍微改进的版本——Christian Heilmann的揭示模块模式。

当我们想要从一个公共方法调用另一个公共方法或访问公共变量时,他不得不重复主对象的名称,这使Heilmann感到沮丧,因此出现了揭示模块模式。他也不喜欢模块模式的要求,因为他希望公开的东西必须切换到对象文字符号。

他努力的结果是一种更新的模式,在这种模式中,我们只需在私有作用域中定义所有函数和变量,并返回一个匿名对象,该对象带有指向我们希望显示为公共的私有功能的指针。

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

优势

这种模式使得脚本的语法更加一致。在模块的末尾,它还使哪些函数和变量可以被公开访问更加清楚,从而降低了可读性。

缺点

这种模式的一个缺点是,如果一个私有函数引用了一个公共函数,那么如果需要一个补丁,这个公共函数就不能被覆盖。这是因为私有函数将继续引用私有实现,并且该模式不应用于公共成员,只应用于函数。

引用私有变量的公共对象成员也遵循上面的无补丁规则。

ES6 Modules命名空间导入

// circle.js
export { name, draw, reportArea, reportPerimeter };
// main.js
import * as Circle from './modules/circle.js';

// draw a circle
let circle1 = Circle.draw(myCanvas.ctx, 75, 200, 100, 'green');
Circle.reportArea(circle1.radius, reportList);
Circle.reportPerimeter(circle1.radius, reportList);

这将获取Circle .js中所有可用的导出,并使它们作为对象Circle的成员可用,有效地为其提供了自己的名称空间。

这是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

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

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

上面的模式非常类似于模块模式,不管你喜欢与否,它允许你将所有函数公开为public,同时避免了对象字面量的刚性结构。

有没有更优雅或更简洁的方式来做到这一点?

是的。例如:

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