3

I have the following code in my javascript module, however this requires me to make the functions visible to the outside world.

var mymodule = function() {
    var self = null,
        init = function () { 
            self = this; 
            $('.actionButton').click(function () {
        var worklistId = $(this).data('worklistid'),
            action = $(this).data('action');
        self[action] && self[action](worklistId); //watchout methods marked as not used are used by this invocation
            })
        },
        send = function () {
             // some logic
        },
        finish = function () {
             // some logic
        },
        delete = function () {
             // some logic
        };

    return {
        init: init,
        send: send,
        finish: finish,
        delete: delete
    };
}();

mymodule.init();

So the only thing I want to return in my module is the init function. However when I do this I cant invoke the functions, because the object (self) only contains the init function visible on the outside.

return {
    init: init
};

Is there any solution to invoke my functions like this without making them visible to the outside world? Please no if else statements, because my workflow is bigger then the 3 actions in this example. I want to make my module as closed as possible because this reduces the dependencies.

Update

Here is a updated jsfiddle with one of the proposed solutions, however this is giving me another issue. http://jsfiddle.net/marcofranssen/bU2Ke/

Marco
  • 4,817
  • 5
  • 34
  • 75

5 Answers5

0

Yes, there is an easy (but perhaps slightly messy) way you can do this without making the functions visible to the global object:

var privateFunctions = { deleter: deleter, send: send};

Then, instead of self[action]();, just do privateFunctions[action](); and you're good to go.

Note that I changed delete to deleter, because delete is a reserved keyword...

Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • While a reserved keyword cannot be a variable name, you can still use it as property name. In the worst case, you can declare it as string: `{'delete': ...}`. – Felix Kling Sep 04 '12 at 11:27
  • I know, but I'm hoping that, one blissful day the list of reserved keywords is going to be cleaned up, while at the same time the usage of keywords (like delete) is going to be completely off-limits. It should be, IMHO. besides, it's not a bad habit to tread keywords as off-limits to avoid any confusion – Elias Van Ootegem Sep 04 '12 at 11:30
  • 1
    No no, I really agree :) Reserved keywords should be off-limits in any situation. But I personally would then use a string literal as key and use bracket notation instead of renaming the key. But that's just personal preference and nothing which has to be discussed here... originally I kust wanted to point out that using `delete` here is not an error, so it does not *have* to be changed, but I concur with your decision. Happy coding! :) – Felix Kling Sep 04 '12 at 13:28
0

Something like this would work:

var mymodule = function() {
        var self = this;
        init = function () { 

            $('.actionButton').click(function () {
        var worklistId = $(this).data('worklistid'), action = $(this).data('action');
        self[action] && self[action](worklistId); //watchout methods marked as not used are used by this invocation
            })
        }
        self.send = function () {
            console.log('send');
        }
        self.finish = function () {
            console.log('finish');
        }
        self.delete = function (item) {
            console.log('delete');
        };

    return {
        init: init,
    };
}();

mymodule.init();​

Here's the fiddle:

http://jsfiddle.net/yngvebn/SRqN3/

By setting the self-variable to this, outside the init-function, and attaching the send, finish and delete functions to self, you can use the self[action] syntax from within the init-function

Yngve B-Nilsen
  • 9,606
  • 2
  • 36
  • 50
  • it failes on the line self.send in my code because self is undefined. Of course I have filled self with this when declaring the var... What am I missing? – Marco Sep 04 '12 at 11:38
  • did you move var self = this; to the beginning of the function like I did? – Yngve B-Nilsen Sep 04 '12 at 11:40
  • Yes I did. First I declare the self variable and put this in it. Then some other variables, then init, then the other functions by doing self.functionname it fails at the first self.functionname – Marco Sep 04 '12 at 11:46
  • Can you post your code in a jsfiddle.net? The above code works just fine in jsfiddle... – Yngve B-Nilsen Sep 04 '12 at 11:47
  • Ah, since you're using "use strict" you're not allowed to throw 'this' around.. I'd look into the answer posted by David here: http://stackoverflow.com/a/12263252/325836 – Yngve B-Nilsen Sep 04 '12 at 12:38
  • @YngveB.Nilsen: You can set the `var self` using the self invoking function, just pass `bis` to the argument self, [here's the slightly altered fiddle](http://jsfiddle.net/bU2Ke/7/) to show what I mean. I haven't looked at the code that much, so I could have passed the wrong object to the closure all together, but [here's](http://stackoverflow.com/questions/12250609/inconsistent-behaviour-of-this-in-javascript-strict-mode) a lot of gob, sprinkled with info. It's a question I'd like to see closed, too so feel free to close-vote – Elias Van Ootegem Sep 04 '12 at 12:52
0
var mymodule = function() {
  var self = {},
     init = function () {  
        $('.actionButton').click(function () {
    var worklistId = $(this).data('worklistid'),
        action = $(this).data('action');
    self[action] && self[action](worklistId); //watchout methods marked as not used are used by this invocation
        })
    };
    self.send = function () {
         // some logic
    };
    self.finish = function () {
         // some logic
    };
    self.delete = function () {
         // some logic
    };
    return{
      init:init
    }
}();

mymodule.init();

This should Work!!

0

Even if you return an object just with the init property and you populate the rest dynamically such that your module uses them, you would still be making them visible to the outside at runtime. Anyone who wants to debug your module would easily get to them.

You can still create anonymous methods at runtime and they would also be visible together with their implementation.

Konstantin Dinev
  • 34,219
  • 14
  • 75
  • 100
0

In your code example, it is vague what "self" really is. You should keep it simple, use encapsulated functions as "private" methods and return a "public" (or "privileged" as Crockford calls it) function that have access to them.

This is the YUI way of doing singletons with private functions and variables. Example pattern:

var mymodule = (function() {
    var internal = {
        'send': function() {},
        'finish': function() {},
        'delete': function() {}
    };
    return {
        'init': function(action) {
            // access to internals, f.ex:
            if ( internal.hasOwnProperty(action) ) {
                 internal[action].call(this); // bring the caller context
            }
         }
    };
}());

mymodule.init('send');
David Hellsing
  • 106,495
  • 44
  • 176
  • 212