views:

35

answers:

2

Let me explain, this is about displaying class source code in IDEs. I have always only one class per file. A class is declared like this in the file mod1.js:

MYGLOB.MOD1.ClassXy = function () {
  //constructor, do somothing
}

MYGLOB.MOD1.ClassXy.prototype.memberfunc1 = function () {
  //member function 1, do somothing
}

(There are many more functions like memberfunc1 in the real class.)

But in different IDEs and editors the width of the function list is now very large. I want the function lists to display only the last part of the function name (the function name itself).

How about this:

ClassXy = function () {
  //constructor, do somothing
}

memberfunc1 = function () {
  //member function 1, do somothing
}

MYGLOB.MOD1.ClassXy = ClassXy;
MYGLOB.MOD1.ClassXy.prototype.memberfunc1 = memberfunc1;

It displays nice in the function list. It does not disturb that there are the 2 long assignments at the bottom of the file. But I have the global namespace polluted. How to do this without affecting the global namespace with the global "ClassXy" and "memberfunc1"? (MYGLOB.MOD1.ClassXy is fine.)

Can I do this with parens / closures somehow or what do you suggest? And keep the effect of having the clean function list in the IDE, at least the first part of the function list showing me the member function with their short names?

Please don't suggest different IDEs or editors, this is not about choosing a different code editor, please open a different question on your own if you want to discuss that. This question is about javascript and classes.

Maybe this is a simple thing, but I am quite new to javascript.

+1  A: 

It will depend a bit on the capabilities of the editors you're using, but the module pattern can be useful for this (and for avoiding global namespace pollution in general). I'll start the answer assuming you're doing this when defining your classes (objects, really), but there's a note at the end about using shorthand aliases when consuming classes (objects) as well.

Basic example of module pattern

var MYGLOB.MOD1.ClassXy = (function() {

    // Define your constructor function
    function ClassXy() {
    }

    // Define your member functions
    function memberfunc1() {
    }

    // Put your member functions on the prototype
    ClassXy.prototype = {
        memberfunc1: memberfunc1
    };

    // Return the constructor function to assign it to the MYGLOB.MOD1 object
    return ClassXy;
})();

There I replaced the prototype; you may want to just add to it instead, in which case I suggest having a utility function somewhere that does a shallow property copy:

function shallowCopy(dest, src) {
    var name;
    for (name in src) {
        // Depending on your needs, you may want to check
        // src.hasOwnProperty(name) here and only copy it
        // when that's true
        dest[name] = src[name];
    }
}

And then replacing the assignment to prototype above with this:

shallowCopy(ClassXy.prototype, {
    memberfunc1: memberfunc1
});

Named functions

Amongst other things, using this pattern means you're using named functions rather than anonymous ones. That helps your tools (debuggers in particular) help you. This format creates an anonymous function and assigns it to a property on an object:

MyObject.functionName = function() { ... }; // Not ideal

Whereas if you use the module pattern, you can declare your functions normally and then assign them to properties later (see above); that way they have names that debuggers can show you in call stacks, etc.

Private utility functions

The pattern also provides a nice way of having utility functions (or class-wide data) used by the class without having to make them public at all -- not on the constructor function, not on its prototype, not on instances. For instance, here's the above with a private utility function:

var MYGLOB.MOD1.ClassXy = (function() {

    // Define your constructor function
    function ClassXy() {
    }

    // Define your member functions
    function memberfunc1() {

        // Call our utility function. In this form, be aware that
        // within the utility, `this` will *not* be set within
        // the utility
        utility('bar');

        // Alternate form if you want to call `utility` as though it
        // were an instance member function; within the utility, it
        // can refer to `this` and have it mean the same thing it
        // means here in `memberfunc1`
        utility.call(this, 'bar');
    }

    // A utility function. This is entirely private to the class,
    // we don't make it a property of anything and so it's never
    // visible outside the closure
    function utility(foo) {
        alert("foo = " + foo);
    }

    // Put your member functions on the prototype
    shallowCopy(ClassXy.prototype, {
        memberfunc1: memberfunc1
    });

    // Return the constructor function to assign it to the MYGLOB.MOD1 object
    return ClassXy;
})();

Using a helper

The above may seem a bit clunky at first, but there's no reason you can't create helpers to make it easier to define classes this way. That's what I've done; using my helper I'd define your example like this:

MYGLOB.MOD1.ClassXy = Class.defineClass(function() {

    // Takes the place of the constructor function; defining it is
    // optional, though, if you don't need to do anything when created
    function initialize() {
    }

    // A member function
    function memberfunc1() {
    }

    // Export our public symbols
    return {
        initialize:  initialize,
        memberfunc1: memberfunc1
    };
});

You can grab the helper (and the reasoning behind it) from my blog post on the topic.

Consuming long-winded APIs

This same pattern can also be turned on its head, when you want to consume an API that's long-winded: Just define a function, pass in the long-winded things as arguments, and use the argument name instead:

(function(xy) {

    // Use the member function; within this closure, xy = MYGLOB.MOD1.ClassXy
    xy.memberfunc1();

})(MYGLOB.MOD1.ClassXy);
T.J. Crowder
thank you for the fast and good explained answer, helps me a lot as a beginner, i will start and try to use it ...
Sven Larson
No worries (you didn't *seem* like a beginner). Good luck with it.
T.J. Crowder
A: 

You can always use an object as a name space. For example, you create an object with short variable name and use it to hold your function. Once ready, you can assign it to your actual production class name.

Fs = new Object();
Fs['ClassXy'] = function() {
    this.time = new Date();
    alert("From ClassXy: " + this.time);
};

Fs['memberfunc1'] = function() {
    alert("From memberfunc1: " + this.time);
};

ClassXy                       = Fs['ClassXy'];
ClassXy.prototype.memberfunc1 = Fs['memberfunc1'];

const aCX1 = new ClassXy();
aCX1.memberfunc1();

The example code above works.

Hope this helps.

NawaMan