如何正确设置JavaScript命名空间和类?

时间:2012-07-25 14:02:51

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

似乎有很多方法可以设置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();

第一种技术感觉更像是一个类。如果这有所不同,我来自服务器端背景。第二种技术似乎更冗余,有点尴尬,但我看到这也使用了很多。有人可以帮助解决一些问题并建议前进的最佳方式吗?我想创建一个有很多类相互交流的应用程序。

5 个答案:

答案 0 :(得分:61)

不要做这些事情。

制作一个javascript“class”:

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!

答案 1 :(得分:6)

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

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

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

然后您可以使用'new'关键字对其进行实例化:

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

答案 2 :(得分:4)

我对命名空间

的可实例化类使用以下语法
 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/

答案 3 :(得分:1)

为什么你永远不应该使用

 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. - 但很容易被其他开发人员阅读和理解。这首先减少了bug的数量。 (c)S. McConnell

答案 4 :(得分:1)

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

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将指向命名空间,因此命名空间将被&#34;销毁&#34;因为MyClass.class_propertyMyClass.class_method会被添加到其中。