3

In want to define a function-constructor inside a namespace. The way in which I defined the constructor till now was a simple constructor function without NS, combined with prototypal inheritance.

The code looked kind of like:

 function mySuperObject() {
    var self = this;
    self.p1 = "";
    self.p2 = "jkejie";
    // and others
    }
 mySuperObject.prototype.func1 = function(){...}
 // and others

Introducing namespace:

After reading many articles I decided to start up with a very simple way to define a namespace, maybe the most simplest. Basically it is just about defining a variable which points to an object-literal and the content is the object (the "mySuperObject" in the code-snippet above). The constructor function is following: mySuperObjectInNS.

The code of the object:

var MYNAMESPACE = {

    //some variable outside the object
    file : "ConstructorInNamespace_obj.js: ",

    //Defining contructor function inside a namespace
    mySuperObjectInNS : function(propOne, propTwo){

        var self = this;
        self.objectName = "mySuperObject";
        self.propertyOne = propOne;
        self.propertyTwo = propTwo;

        self.doSomething = function(){
            console.log(file + " doSomething called - function of object");
        };

        ///many more functions and attributes
    }
}

MYNAMESPACE.mySuperObjectInNS.prototype.specialFunction = function(){
    console.log(file + " specialFunction called - prototypical inheritance defined in file of object, outside of namespace");
};

///many more functions and attributes

In another file it is possible to intantiate the object, as follows:

...
var objOne = new MYNAMESPACE.mySuperObjectInNS("param11", "40");
//following line works just fine
objOne.doSomething();
 ....

Questions:

  • It seems to me that this all is about defining an Object-Literal and I will come into trouble the latest I am trying to define "private" properties of that object. Is this correct?
  • Is that mySuperObjectInNS still a constructor function? (For me it seems it is something else,even if I can intantiate objects from it.
  • Is is a very bad very bad way of namespacing or is kind of ok?

1 Answer 1

4

It seems to me that this all is about defining an Object-Literal and I will come into trouble the latest I am trying to define "private" properties of that object. Is this correct?

"Private properties" have nothing to do with using an object for namespacing. In fact, originally when answering this question, I read that as "private functions" because that would be relevant.

There are lots of ways to do private and semi-private properties in JavaScript, but they relate to how you create the constructor function and the methods it gives the object, not how you expose the constructor function. "Namespace" objects are about how you expose the constructor.

One common pattern for creating "private" properties is to define methods that need to access them within the constructor, and make the "properties" local variables within the constructor (so they aren't really properties at all), like this:

function SuperObject() {
    var privateInformation;

    this.method = function() {
        // This can access `privateInformation`, which is completely
        // hidden from outside the constructor
    };
}

It doesn't matter at all if you do that within a "namespacing" pattern or on its own.

Private functions, on the other hand, affect the pattern. I'll show both below.

A fairly common variant that provides for private functions is to use a function to create the object, which also gives you the opportunity to create private functions:

var TheNamespace = function() {
    function privateFunction() {
    }

    function SuperObject() {
        var privateInformation;

        this.method = function() {
            // This can access `privateInformation`, which is completely
            // hidden from outside the constructor
        };
    }

    SuperObject.prototype.otherMethod = function() {
        // Can't access `privateInformation`, but has the advantage
        // that the function is shared between instances
    };

    return {
        SuperObject: SuperObject
    };
}();

// usage
var s = new TheNamespace.SuperObject();

Is that mySuperObjectInNS still a constructor function? (For me it seems it is something else,even if I can intantiate objects from it.

Yes. A constructor function is any function that expect you to use new with it.

Is is a very bad very bad way of namespacing or is kind of ok?

Using objects as pseudo-namespaces is common practice. You might also consider various asynchronous module definition (AMD) technologies, which largely make "namespace" objects largely unnecessary.


Re your comment:

You defined a self-invoking function....which returns an an object?

It's not a self-invoking function, it's an inline-invoked function, but yes, it's a function that returns an object.

(if so I think parantheses are missing)

No, we don't need any parens that aren't there because the only reason for the outer parens other places you've seen this are to tell the parser that the word function starts an expression rather than declaration; we don't need that in the above because we're already on the right-hand side of an assignment, so there's no ambiguity when function is encountered.

Due to you proposed this way, is it a better way to define the ns?

"Better" is a subjective term. It gives you a scope in which you can define private functions, which you'd asked about.

Whereas I often also saw the option: var = {} | someNSName; What is this all about?

If you have several files that will add things to the "namespace" (as is common), then you frequently see this in each of them:

var TheNamespace = TheNamespace || {};

What that does is declare the variable if it hasn't been declared before, and assign an empty object to it if it doesn't already have one. In the first file that gets loaded, this happens:

  1. The var is processed and creates a new variable, TheNamespace, with the value undefined.

  2. The TheNameSpace = TheNameSpace || {} assignment is processed: Since undefined is falsey, the curiously-powerful || operator results in the new {}, which gets assigned to TheNamespace.

When the next file loads, this happens:

  1. The var is a no-op, because the variable already exists.

  2. The TheNameSpace = TheNameSpace || {} assignment is processed: Since TheNamespace has a non-null object reference, it's truthy, and the curiously-powerful || operator results in a reference to the object TheNamespace refers to.

That is, it has no effect at all.

This is used so you can load the files in any order, or load just one file in isolation.

Here's an example:

thingy.js:

var TheNamespace = TheNamespace || {};
TheNamespace.Nifty = function() {
    function privateFunction() {
    }

    function Nifty() {
        var privateInformation;

        this.method = function() {
            // Can access `privateInformation` here
        };
    }

    Nifty.prototype.otherMethod = function() {
        // ...
    };

    return Nifty;
}();

thingy.js:

var TheNamespace = TheNamespace || {};
TheNamespace.Thingy = function() {
    function privateFunction() {
    }

    function Thingy() {
        var privateInformation;

        this.method = function() {
            // Can access `privateInformation` here
        };
    }

    Thingy.prototype.otherMethod = function() {
        // ...
    };

    return Thingy;
}();

There are lots of variations on that basic pattern, particularly if one file may add multiple things to TheNamespace. Here's one that supports doing so fairly concisely:

var TheNamespace = function(exports) {
    function privateFunction() {
    }

    function Nifty() {
        var privateInformation;

        this.method = function() {
            // Can access `privateInformation` here
        };
    }

    Nifty.prototype.otherMethod = function() {
        // ...
    };

    exports.Nifty = Nifty;

    function Thingy() {
        var privateInformation;

        this.method = function() {
            // Can access `privateInformation` here
        };
    }

    Thingy.prototype.otherMethod = function() {
        // ...
    };

    exports.Thingy = Thingy;
}(TheNamespace || {});
Sign up to request clarification or add additional context in comments.

8 Comments

Hello Crowder. Thank you for the good response, though I have a question: You defined a self-invoking function (if so I think parantheses are missing), which returns an an object? Due to you proposed this way, is it a better way to define the ns? As it is a common practise, I guess I can use it. Whereas I often also saw the option: var = {} | someNSName; What is this all about? (Or should I post an extra question...?)
@Meru: I've added to the answer to address those follow-up questions.
Thanks a lot for the answers. Whereas one thing: In the meantime I tried to "create" private variables in the object-literal and I think it worked out. I will post it as "answer", otherwise difficult to describe. I hope this is not as against the rules here.Meru
Once more it's me. How about defining the functions with function-expressions like: var mysuperFunction = function () {....} ?
@Meru: In the context of the above, it doesn't matter whether you use a function expression (var mySuperFunction = function() { ... }) or a function declaration (function mySuperFunction() { ... }).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.