web-dev-qa-db-fra.com

Comment configurer correctement l'espace de noms et les classes JavaScript?

Il semble qu'il existe de nombreuses façons de configurer une application JavaScript, il est donc difficile de savoir laquelle est correcte ou la meilleure. Y a-t-il une différence entre les techniques ci-dessous ou une meilleure façon de procéder?

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

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

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

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

Autrement:

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

La première technique se sent plus comme une classe. Je viens de l'arrière-plan côté serveur si cela fait une différence. La deuxième technique semble plus redondante et un peu gênante, mais je vois que cela est également très utilisé. Quelqu'un peut-il aider à faire la lumière et à vous conseiller sur la meilleure façon d'avancer? Je veux créer une application avec beaucoup de classes qui se parlent.

41
TruMan1

Ne faites rien de tout cela.

Créez une "classe" 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();

Un avec vars statiques:

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

Avec un "constructeur" (tous les exemples ont un "constructeur", celui-ci a juste des paramètres avec lesquels travailler):

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

Avec tout ce qui précède, vous pouvez le faire:

MyNamespace.MyClass.someFunction();

Mais vous ne pouvez pas faire (de l'extérieur):

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

Le premier exemple est simplement un Object literal - il ne peut pas être instancié et n'a pas de membres privés. Le deuxième exemple a une syntaxe incorrecte (var someProperty: 5 devrait être var someProperty = 5) mais utilise une fermeture pour encapsuler l'état privé interne dans une fonction anonyme auto-invoquante.

La seconde approche semble meilleure pour encapsuler des membres privés, mais pourrait être rendue plus "orientée objet" en en faisant une classe instanciable:

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

Ensuite, vous pouvez l'instancier avec le "nouveau" mot clé:

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

J'utilise la syntaxe suivante pour les classes instanciables avec namespace

 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
Razan Paul

Pourquoi vous ne devriez jamais utiliser

 return { methodName : methodDelegate}

comme dans le deuxième exemple:

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

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

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

MyNamespace.MyClass.init();

Lorsque vous utilisez un espace de noms, vous devez le considérer comme une déclaration, et non l'instance.

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

Et aucun compteur combien le module anti-patter était populaire. La déclaration vous donne la possibilité d'utiliser le même code avec différentes instances d'une manière attendue pour d'autres développeurs. La qualité du code et la simplicité de sa lecture augmentent. Le but de tout développeur est d'écrire un code simple à lire, pas un code plus court ou D.R.Y. - mais simple à lire et à comprendre par un autre développeur. Cela diminue d'abord le nombre de bogues. c) S. McConnell

1
Artem G

Comment combiner espace de noms et déclaration de classe:

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

Accéder à votre valeur:

console.log(ns.my_value);

Maintenant, pour la classe et la fonction: Si vous utilisez new, le mot this à l'intérieur de la fonction pointera vers son constructeur. Si vous n'utilisez pas new, this pointera vers l'espace de noms. Donc,

Utilisation d'une classe:

var obj = new ns.MyClass();

Utilisation de la fonction:

ns.myFunction();

Si vous construisez l'objet sans new, this pointera vers l'espace de noms, donc l'espace de noms sera "détruit" car MyClass.class_property et MyClass.class_method y sera ajouté.

1
marirena