Как правильно настроить пространство имен и классы JavaScript?

Кажется, что существует так много способов настроить приложение 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();

Первый метод по ощущениям больше похож на класс. Я исхожу из фона на стороне сервера, если это имеет значение. Второй метод кажется более избыточным и немного неудобным, но я вижу, что он тоже часто используется. Может кто-нибудь помочь пролить свет и посоветовать лучший способ двигаться вперед? Я хочу создать приложение с большим количеством классов, разговаривающих друг с другом.


person TruMan1    schedule 25.07.2012    source источник
comment
Это не столько использование ООП JS, сколько использование шаблона модуля.   -  person zzzzBov    schedule 25.07.2012
comment
Кроме того, вы подразумеваете, что два метода эквивалентны, но второй метод недействителен. То, как вы объявили частные переменные, синтаксически недопустимо, вам просто нужен обычный оператор var.   -  person alexp    schedule 25.07.2012
comment
Спасибо, я исправил второй метод.   -  person TruMan1    schedule 25.07.2012


Ответы (5)


Не делайте ни того, ни другого.

Сделайте 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!
person Naftali aka Neal    schedule 25.07.2012
comment
Как мне обрабатывать init или конструктор? - person TruMan1; 25.07.2012
comment
@TruMan1 конструктор - это то, что вы передаете в new MyClass(). Добавлю пример с конструктором. - person Naftali aka Neal; 25.07.2012
comment
Конструктор не обязательно должен иметь параметры. - person nnnnnn; 25.07.2012
comment
@nnnnnn это правда. Я просто положил его туда для чутья. - person Naftali aka Neal; 25.07.2012
comment
@nnnnnn Я добавил это примечание к сообщению. - person Naftali aka Neal; 25.07.2012
comment
Как мне избежать конфликтов с другой загруженной библиотекой, которая также создает var MyClass в глобальном пространстве имен? Нет ли способа обойти это и нужно ли выбирать очень уникальные имена для моих классов, например var TrumanMyClass = function ()...? - person TruMan1; 25.07.2012
comment
Или просто назовите свой класс в своем пространстве имен ^_^ нет причин делать его глобальным, я просто поместил его в качестве примера - person Naftali aka Neal; 25.07.2012
comment
Как тогда вы можете определить класс непосредственно в пространстве имен? Я боролся с этим уже пару дней - явно что-то с дизайном JavaScript, которого я не понимаю... :( - person thomthom; 11.06.2013
comment
Многое узнал из этого ответа. Спасибо друг. - person ; 04.12.2013
comment
Рад помочь @DeeMac :-) - person Naftali aka Neal; 05.12.2013
comment
Разве этот ответ не нуждается в обновлении с ES6? developer.mozilla.org/en-US/docs/Web/ JavaScript/Справочник/ - person Sl4rtib4rtf4st; 01.06.2020
comment
Не то, чтобы я знал о @ Sl4rtib4rtf4st - class - это в основном синтаксический сахар вокруг того, что здесь существует. - person Naftali aka Neal; 03.06.2020

Первый пример — это просто литерал объекта. т есть частные члены. Второй пример имеет некоторый неправильный синтаксис (var someProperty: 5 должен быть var someProperty = 5), но использует замыкание для инкапсуляции внутреннего частного состояния в самовызывающуюся анонимную функцию.

Второй подход выглядит лучше для инкапсуляции закрытых членов, но его можно сделать более «объектно-ориентированным», сделав его экземплярным классом:

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

Затем вы можете создать его с помощью ключевого слова «новое»:

var aClass = new MyNamespace.MyClass();
aClass.init(...);
person chrisfrancis27    schedule 25.07.2012

Я использую следующий синтаксис для инстанцируемых классов с пространством имен

 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/

person Razan Paul    schedule 10.12.2014

Почему вы никогда не должны использовать

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

И неважно, насколько популярен модуль Anti-Patter. Декларация дает вам возможность использовать один и тот же код с разными экземплярами ожидаемым образом для других разработчиков. Повышается качество кода и простота его чтения. Цель любого разработчика — написать простой код, который будет читаться, а не более короткий или D.R.Y. - но простой для чтения и понимания другим разработчиком. Это в первую очередь уменьшает количество ошибок. (с) С. МакКоннелл

person Artem G    schedule 30.01.2015

Как объединить пространство имен и объявление класса:

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 внутри функции будет указывать на ее конструктор. Если вы не используете new, this будет указывать на пространство имен. Так,

Использование класса:

var obj = new ns.MyClass();

Использование функции:

ns.myFunction();

Если вы создадите объект без new, this будет указывать на пространство имен, поэтому пространство имен будет «уничтожено», потому что к нему будут добавлены MyClass.class_property и MyClass.class_method.

person marirena    schedule 28.09.2016