【问题标题】:How to set up JavaScript namespace and classes properly?如何正确设置 JavaScript 命名空间和类?
【发布时间】:2012-07-23 23:46:36
【问题描述】:

似乎有很多方法可以设置 JavaScript 应用程序,所以很难确定哪一种是正确的或最好的。以下技术或更好的方法有什么不同吗?

MyNamespace.MyClass = {
    someProperty: 5,
    anotherProperty: false,

    init: function () {
        //do initialization
    },

    someFunction: function () {
        //do something
    }
};

$(function () {
    MyNamespace.MyClass.init();
});

另一种方式:

MyNamespace.MyClass = (function () {
    var someProperty = 5;
    var anotherProperty = false;

    var init = function () {
        //do something
    };

    var someFunction = function () {
        //do something
    };

    return {
        someProperty: someProperty
        anotherProperty: anotherProperty
        init: init
        someFunction: someFunction
    };
}());

MyNamespace.MyClass.init();

第一种技术感觉更像是一门课。如果这有所作为,我来自服务器端背景。第二种技术似乎更多余,也有点尴尬,但我也看到它被大量使用。有人可以帮忙阐明一下并建议前进的最佳方式吗?我想创建一个应用程序,其中包含许多相互通信的类。

【问题讨论】:

  • 这不是使用 OOP JS 而是使用模块模式。
  • 另外,您暗示这两种方法是等效的,但第二种方法无效。你声明私有变量的方式在语法上是无效的,你只需要一个常规的 var 语句。
  • 谢谢我修正了第二种方法。
  • 如果您有兴趣了解更多信息,我强烈推荐 Douglas Crockford 的 Javascript: The Good Parts。他不仅提供了经典 OOP 的 Javascript 方法,还解释了如何使用 Javascript 的更多类似 LISP 的部分来创建其他一些令人惊叹的结构。从头开始,他解释了每种结构的工作原理和原因,以及最有效的方法。此外,您可能个人有兴趣学习CoffeeScript,尤其是其内置的class structure

标签: javascript oop javascript-framework javascript-objects javascript-namespaces


【解决方案1】:

这两件事都不做。

制作一个javascript“类”:

var MyClass = function () {

    var privateVar; //private
    var privateFn = function(){}; //private 

    this.someProperty = 5;  //public
    this.anotherProperty = false;  //public
    this.someFunction = function () {  //public
        //do something
    };

};

MyNamespace.MyClass = new MyClass();

一个带有静态变量的:

var MyClass = (function(){

    var static_var; //static private var

    var MyClass = function () {

        var privateVar; //private
        var privateFn = function(){}; //private 

        this.someProperty = 5;  //public
        this.anotherProperty = false;  //public
        this.someFunction = function () {  //public
            //do something
        };
    };

    return MyClass;

})();

MyNamespace.MyClass = new MyClass();

使用“构造函数”(所有示例都有一个“构造函数”,这个只有参数可以使用):

var MyClass = function (a, b c) {

    //DO SOMETHING WITH a, b, c <--

    var privateVar; //private
    var privateFn = function(){}; //private 

    this.someProperty = 5;  //public
    this.anotherProperty = false;  //public
    this.someFunction = function () {  //public
        //do something
    };

};

MyNamespace.MyClass = new MyClass(1, 3, 4);

有了以上所有你可以做到

MyNamespace.MyClass.someFunction();

但你做不到(从外部):

MyNamespace.MyClass.privateFn(); //ERROR!

【讨论】:

  • 我如何处理 init 或构造函数?
  • @TruMan1 “构造函数”是您传入new MyClass() 的任何内容。我将添加一个带有构造函数的示例。
  • “构造函数”不必有参数。
  • @nnnnnn 这是真的。我只是把它放在那里。
  • 如何避免与另一个在全局命名空间中创建“var MyClass”的加载库发生冲突?有没有办法解决这个问题,必须为我的类选择非常独特的名称,比如“var TrumanMyClass = function ()...”?
【解决方案2】:

第一个例子只是一个Object literal - 它不能被实例化并且没有私有成员。第二个示例有一些不正确的语法(var someProperty: 5 应该是 var someProperty = 5),但是使用闭包将内部私有状态封装在自调用匿名函数中。

第二种方法看起来更适合封装私有成员,但可以通过使其成为可实例化的类来使其更加“面向对象”:

MyNamespace.MyClass = function() { ... };
MyNamespace.MyClass.prototype.someProperty = 'foo';

然后你可以用'new'关键字来实例化它:

var aClass = new MyNamespace.MyClass();
aClass.init(...);

【讨论】:

    【解决方案3】:

    我对带有命名空间的可实例化类使用以下语法

     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/

    【讨论】:

      【解决方案4】:

      为什么你不应该使用

       return { methodName : methodDelegate}
      

      就像第二个例子:

      MyNamespace.MyClass = (function () {
          var someProperty = 5;
      
          var init = function () {
              //do something
          };
      
          return {
              someProperty: someProperty
              someFunction: someFunction
          };
      }());
      
      MyNamespace.MyClass.init();
      

      当您使用命名空间时,您必须将其视为声明,而不是实例。

      MyNamespace = {};
      MyNamespace.sub = {};
      MyNamespace.anotherSub = {};
      MyNamespace.sub.MyClass = (function () {
      
          var static_var; //static private var
      
          var MyClass2 = function () {
      
              var privateVar; //private
              var privateFn = function () { }; //private 
      
              this.someProperty = 5;  //public
              this.anotherProperty = false;  //public
              this.someFunction = function () {  //public
                  //do something
              };
          };
      
          return MyClass2;
      
      })();
      debugger;
      
      var c1 = new MyNamespace.sub.MyClass();
      c1.someProperty = 1; // creates 5->1.
      
      var c2 = new MyNamespace.sub.MyClass();
      c2.someProperty = 2;  // creates 5->2. c1 is still 1
      
      
      
      debugger;
      var myClass = function () {
          var someProperty = 5;
          var anotherProperty = false;
      
          var init = function () {
              //do something
          };
      
          var someFunction = function () {
              //do something
          };
      
          return {
              someProperty: someProperty,
              anotherProperty: anotherProperty,
              init: init,
              someFunction: someFunction
          };
      };
      
      
      MyNamespace.MyClass = myClass();
      var c2 = MyNamespace.MyClass;
      // how  are planning to create one more object, while it's a reference? copy      //the whole one?
      
      c2.someProperty = 2; // changes 5 -> 2
      var c3 = MyNamespace.MyClass.init(); // create 2 instead of 5
      
      c3.someProperty = 3;    // changes c3 and c3 from 2 to 3.
      console.log(c2.someProperty + c3.someProperty);
      

      无论模块反模式有多受欢迎。声明使您能够以其他开发人员预期的方式将相同的代码用于不同的实例。代码的质量和阅读的简单性提高了。任何开发人员的目标都是编写一个简单的代码以供阅读,而不是更短的代码或 D.R.Y. - 但很容易被其他开发人员阅读和理解。这首先减少了错误的数量。 (c) S.麦康奈尔

      【讨论】:

        【解决方案5】:

        如何结合命名空间和类声明:

        var ns = { // your namespace
            my_value: 1, // a value inside the namespace to avoid polluting
            MyClass: function() { // a class inside the namespace
                this.class_property: 12,
                this.class_method: function() {
                    console.log("My property: " + this.class_property);
                }
            },
            myFunction: function() { // a function inside a namespace
                console.log("I can access namepsace value if you don't use 'new': " + this.my_value);
            }
        };
        

        获取您的价值:

        console.log(ns.my_value);
        

        现在,对于类和函数:如果您使用new,则函数内的单词this 将指向它的构造函数。如果不使用newthis 将指向命名空间。所以,

        使用类:

        var obj = new ns.MyClass();
        

        使用函数:

        ns.myFunction();
        

        如果你在没有new的情况下构造对象,this将指向命名空间,因此命名空间将被“销毁”,因为MyClass.class_propertyMyClass.class_method将被添加到其中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-10-12
          • 1970-01-01
          • 2022-07-10
          • 1970-01-01
          • 1970-01-01
          • 2011-04-12
          • 2014-07-15
          • 1970-01-01
          相关资源
          最近更新 更多