开发者

Is this proper javascript for making a namespace that encapsulates various methods into different objects?

开发者 https://www.devze.com 2023-01-27 16:53 出处:网络
var namespaced = { A: function(){ function r(){ //do some stuff re开发者_如何学Cturn something; } var someProperty = 5;
var namespaced = {
    A: function(){
        function r(){
            //do some stuff
            re开发者_如何学Cturn 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
        }    
    }
}

Then I could do...

namespaced.A.j();

namespaced.C.d();

something = namespaced.A.someProperty;

right?

Would I need to do this too?

var something = new namespaced.A()?

If so does A() have a constructor? I'm really confused here :{

I'm trying to encapsulate my javascript so it's easy to maintain


Then I could do...

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

No you couldn't. The function j and someProperty are only local to A and are not propagated to the outside. If you want to access them from the outside, you have to make them a property of the function, using 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;
        };
    }
}

But you would still need to call var a = new namespaced.A() in order to access the functions.

If you want to call namespaced.A.j() directly, you would have to declare A as object, not as function:

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

        someProperty: 5,     

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

So it depends on what you want to achieve eventually... to get a better insight into these methods, I recommend JavaScript Patterns.


This is what you need to understand about JavaScript:

  • When you write
    var obj = { A: a, B: b, C: c };

you are creating (and assigning to obj) an object with properties called A, B and C mapping to values a, b and c respectively. These values may very well be functions, so when you have

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

you are creating an object with a property called "A" which is a function. You can refer to it with obj.A and call with obj.A().

  • When you call obj.A(), the keyword this inside the body of function A will refer to obj. You can use it to assign new properties to obj:
    var obj = {  
        A: function() { this.prop = "Hello!"; }
    };  
    obj.A();  
    alert( obj.prop ); // alerts "Hello!"

So, inside namespaced.A.j() the this keyword will point to namespace.A (it's what is to the left of the last dot).

  • You can apply a function to an object like so: func.apply(obj) or like so: func.call(obj). In this case, the this keyword will refer to obj instead. This isn't relevant to your case, but if func takes parameters (let's say param1 and param2), you can apply the function like so: func.apply(obj, [val1, val2]) or like so: func.call(obj, val1, val2).

  • All variables declared inside a function live only inside that function. They are not visible outside. And when you write function doStuff(){} it's (I'm simplifying here) as good as if you wrote var doStuff = function(){}; So nested functions live and can be used only inside the surrounding function; that is, unless you assign them to something accessible from outside.

  • When you call something like new Cons() what happens is the creation of a new empty object followed by the application of Cons() on that object. In other words, it's the same as

        var obj = {};
    Cons.apply(obj);
    
    or if you prefer:

    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! :)

So you can have this:

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


With all the preceding in mind, a way to write namespaced code is like this:

// 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"

I hope this helps more than it confuses.

0

精彩评论

暂无评论...
验证码 换一张
取 消