Это правильный javascript для создания пространства имен, которое инкапсулирует различные методы в разные объекты? - PullRequest
2 голосов
/ 01 декабря 2010
var namespaced = {
    A: function(){
        function r(){
            //do some stuff
            return something;
        }

        var someProperty = 5;     

        function j(){
            //do some more stuff
            return something;
        }     
    },

    B: function(){   
        //can I call A and C?
        A.r();
        C.d();
    },

    C: function(){
        function d() {
            //do stuff we like
        }    
    }
}

Тогда я мог бы сделать ...

namespaced.A.j();

namespaced.C.d();

something = namespaced.A.someProperty;

право

Должен ли я сделать это тоже?

var something = new namespaced.A()?

Если так, то у A () есть конструктор? Я действительно запутался здесь: {

Я пытаюсь инкапсулировать свой JavaScript, чтобы его было легко поддерживать

Ответы [ 2 ]

4 голосов
/ 01 декабря 2010

Тогда я мог бы сделать ...

namespaced.A.j();
namespaced.C.d();
something = namespaced.A.someProperty;

Нет, ты не мог. Функции j и someProperty являются локальными только для A и не распространяются наружу. Если вы хотите получить к ним доступ извне, вы должны сделать их свойством функции, используя this:

var namespaced = {
    A: function(){
        this.r = function(){
            //do some stuff
            return something;
        };

        this.someProperty = 5;     

        this.j = function(){
            //do some more stuff
            return something;
        };
    }
}

Но для доступа к функциям вам все равно необходимо вызвать var a = new namespaced.A().

Если вы хотите вызвать namespaced.A.j() напрямую, вам нужно объявить A как объект, а не как функцию:

var namespaced = {
    A: {
        r: function(){
            //do some stuff
            return something;
        },

        someProperty: 5,     

        j: function(){
            //do some more stuff
            return something;
        }     
    }
}

Так что это зависит от того, чего вы хотите достичь в конечном итоге ... чтобы лучше понять эти методы, я рекомендую Шаблоны JavaScript .

2 голосов
/ 02 декабря 2010

Вот что вам нужно понять о JavaScript:

  • Когда вы пишете
    var obj = { A: a, B: b, C: c };

вы создаете (и присваиваете obj) объект со свойствами, именуемыми A, B и C, сопоставляя значения a, b и c соответственно. Эти значения вполне могут быть функциями, поэтому, когда у вас есть

    var obj = { A: function(){...} };

вы создаете объект со свойством «A», которое является функцией. Вы можете обратиться к нему с помощью obj.A и позвонить с помощью obj.A().

  • Когда вы вызываете obj.A(), ключевое слово this внутри тела функции A будет ссылаться на obj. Вы можете использовать его для назначения новых свойств obj:
    var obj = {  
        A: function() { this.prop = "Hello!"; }
    };  
    obj.A();  
    alert( obj.prop ); // alerts "Hello!"

Итак, внутри namespaced.A.j() ключевое слово this будет указывать на namespace.A (это то, что слева от последней точки).

  • Вы можете применить функцию к объекту примерно так: func.apply(obj) или примерно так: func.call(obj). В этом случае ключевое слово this будет ссылаться на obj. Это не относится к вашему случаю, но если func принимает параметры (скажем, param1 и param2), вы можете применить функцию следующим образом: func.apply(obj, [val1, val2]) или примерно так: func.call(obj, val1, val2).

  • Все переменные, объявленные внутри функции, живут только внутри этой функции. Они не видны снаружи. И когда вы пишете function doStuff(){}, это (я упрощаю здесь) так же хорошо, как если бы вы написали var doStuff = function(){}; Таким образом, вложенные функции живут и могут использоваться только внутри окружающей функции; то есть, если вы не назначите их для чего-то доступного извне.

  • Когда вы вызываете что-то вроде new Cons(), происходит создание нового пустого объекта с последующим применением Cons() к этому объекту. Другими словами, это так же, как

        var obj = {};
    Cons.apply(obj);
    
    или, если вы предпочитаете:
    var obj = {};
    obj.Cons = Cons;
    obj.Cons();
    // obj's Cons property then mysteriously disappears
    // unless it was explicitly set inside Cons() (oh my, how confusing! :)

Так что вы можете иметь это:

    function Duck(name){
        this.myName = name;
        this.quack = function(){
            alert(this.myName + " quacks!");
        }
    };
    donald = new Duck('Donald');
    donald.quack();

<ч /> Учитывая все вышесказанное, способ написания кода с пространством имен выглядит следующим образом:

// The following syntax, confusing to someone who hasn't seen it before,
// is defining a new anonymous function and immediately using it
// as a constructor applied to a new empty object.
//
// Alternatively, you can use this syntax:
//   var namespaced = {};
//   (function(){
//       ....
//   }).apply(namespaced);
//
var namespaced = new (function(){

    // This creates a new variable named "namespaced"
    // which is visible only inside this anonymous function.
    // This variable points to the still-empty object created by
    // 'new'. This object will, once we're done with this anonymous function,
    // be assigned to a variable, outside, which by "coincidence" is
    // also named "namespaced".
    var namespaced = this;

    // You could alternatively not create the variable "namespaced"
    // and use 'this' directly inside this anonymous function. But,
    // the 'this' keyword may point to different objects inside the
    // nested functions that follow, so we create it to avoid confusion.


    // This assigns a new object to variable 'A', which isn't visible outside.
    // Use a constructor function defined inline.
    var A = new (function(){
        var A = this;  // 'this' now refers to the empty object created just above

        this.someProperty = 5;  // Two different ways of
        A.anotherProperty = 7;  // doing mostly the same thing

        this.j = function(){
            //do some more stuff
            // 'this' will point to j, here
            return something;
        }

        // Function r isn't visible outside of A's constructor like this!
        function r(){
            //do some stuff
            return something;
        }

        // Make 'r' visible outside by assigning it to a property of 'A'.
        // Look, it's also called "r". What fun!
        A.r = r;
    })();

    // Make the object in variable 'A' visible outside of
    // 'namespaced's constructor, by making it a property of 'namespaced'
    namespaced.A = A;


    // Create a new object as before.
    // This time we won't make it visible outside
    // of "namespaced"'s constructor.
    var C = new (function(){
        this.d = function (){
            //do stuff we like
        }    
    })();


    // Give "namespaced" a property 'B'.
    // This time it's a function instead of a nested object.
    namespaced.B = function(){
        // It's cool to make these function calls here, because
        // (a) nested functions can see the variables ('A' & 'C')
        // of surrounding functions, even if they terminate in the meantime;
        // and (b) 'r' & 'd' are properties of 'A' and 'C'.
        A.r();
        C.d();
    };


    // You could return 'this' or 'namespaced' from this constructor,
    // but the 'new' keyword will make sure the "namespaced" variable
    // outside will get the no-longer-empty object it created,
    // so you can just not return anything.
})();





// Now you can do
five = namespaced.A.someProperty;
seven = namespaced.A.anotherProperty;

something = namespaced.A.j();

namespaced.B(); // Calls A.r() and C.d()

// But you can't do
namespaced.C.d(); // WRONG: "namespaced" doesn't have a property named "C"

Надеюсь, это поможет больше, чем запутает.

...