How can i call a public method from within a private one when using the javascript Module Pattern?
Asked Answered
L

2

9

I would like to call a public method from a private one but the property "this" refers to the window object.

Please note i am trying to apply the module pattern. You can find a working code example at jsfiddle.net

// how can i access a public method from a private one?
// (in this example publicAlert from privateMethod)
// this refers to the window object.

$(function() {
var modulePattern = (function($)
{
    var privateMethod = function()
    {
        appendText("called privateMethod()");
        this.publicAlert();
    };

    var appendText = function(texToAppend)
    {
        var text = $('#output').text() + " | " + texToAppend;
        $('#output').text(text);
    };

    return {
        publicMethod : function()
        {
            appendText("called publicMethod()");
            privateMethod();
        },

        publicAlert : function()
        {
            alert("publicAlert");
        }
    };
});

mp = new modulePattern($);
mp.publicMethod();
});
Lillylillywhite answered 21/12, 2010 at 23:56 Comment(2)
Yeah, you're not using the module pattern correctly. You should be executing the anonymous function immediately, rather than using 'new' And you should never have to use the 'this' keyword either. You also don't need to wrap the module inside jquery's ready handler, only the calls to it. See this: jsfiddle.net/sVxvzHectorhecuba
Good answer is already there: #1112225Subversion
H
11

If you want to be able to do that you need to declare the 'public' function like you would a private function, and then expose it as public. Like this:

$(function() {
    var modulePattern = (function($) {
        var privateMethod = function() {
            appendText("called privateMethod()");
            publicAlert();
        };

        var appendText = function(text) {
            var text2 = $('#output').text() + " | " + text;
            $('#output').text(text2);
        };

        var publicAlert = function(){
            alert("publicAlert");            
        };

        return {
            publicMethod: function() {
                appendText("called publicMethod()");
                privateMethod();
            },

            publicAlert: publicAlert
        };
    });

    mp = new modulePattern($);
    mp.publicMethod();
});

[Edit] I would also encourage you to get into the habit of clicking on the 'jslint' button at the top of jsfiddle, your code was missing a few semicolons, and you also redeclared the 'text' variable inside your appendText function (it was already passed in)

Also, you're using the module pattern in a slightly different way to how I've learned it. Do you have a link to your reference material?

This is how I would have done the module pattern as I know it: http://jsfiddle.net/sVxvz/ [/Edit]

Also, if you use the module pattern correctly, you can refer to the public functions by using the module name, like this:

var testModule = (function($) {
    var privateMethod = function() {
        appendText("called privateMethod()");
        testModule.publicAlert();
    };

    var appendText = function(text) {
        var text2 = $('#output').text() + " | " + text;
        $('#output').text(text2);
    };

    return {
        publicMethod: function() {
            appendText("called publicMethod()");
            privateMethod();
        },
        publicAlert: function() {
            alert("publicAlert");
        }
    };
}(jQuery));

$(function() {
    testModule.publicMethod();
});

But I don't really like this because the public methods can be overwritten. someone could go testModule.publicAlert = function(){EVIL CODE OF DOOM;}; and your internal workings will happily execute it.

Hectorhecuba answered 22/12, 2010 at 0:6 Comment(8)
Thanks for your feedback. And sorry about the unclean code, i totally forgot the jslint button because i was thinking about my issue :) Here are two of the sources i use as reference for the pattern: yuiblog and ajaxianLillylillywhite
I think your solution will be the easiest one but besides remaping the publicAlert method from private to public, isnt there a way to inject the correct scope for "this"?Lillylillywhite
taking @david's suggestion and making it to where you do not have to double define public methods/properties jsfiddle.net/subhaze/JJwrU/3Stasny
Yeah, in both those links they autoexecute the function, which you're not doing. Did you check the link I added at the bottom? jsfiddle.net/sVxvz Also subhaze, I'm not double defining the public methods, they are defined once, and then exposed through the return object. It's similar to what you've done, except you're building the return object before returning it, which allows the internal functions to see it. Quite clever!Hectorhecuba
And re: 'injecting the correct scope for "this"' - what you're asking doesn't really make sense. The module pattern should never involve the 'this' keyword.Hectorhecuba
@Hectorhecuba where does the pattern say that you have to auto execute it? I thought its open to the developer. Basically you create a singelton when you autoexecute it. Woudlnt it be possible to assign "this" to a variable named "that" in an init method and use "that" to get the correct scope? But that solution sounds way more complicated than the two posted. I cant decide which method to prefer, the one posted by you or subhaze. :)Lillylillywhite
Because the autoexecuting is a huuuge part of the pattern. You're not creating a new object, you're creating an anonymous function scope, immediately executing it to create a closure around the internal 'private' variables, and then returning a specially tailored object to allow limited access to the functions that are trapped within the closure.Hectorhecuba
If you want to have multiple 'copies' of a module, then you can execute the function multiple times, each time creating a new closure. But you never use the 'new' keyword. This is how I would do it: jsfiddle.net/qGtJXHectorhecuba
U
0

I understand this is a little bit different from the module pattern, but I think it still offers the same benefits of encapsulation. Public methods are declared as:

this.methodName = function(){...}

the variable $this is assigned to the current instance (this), so you can use it from within private (or public) methods to access any methods or attributes on that instance.

Fork:

http://jsfiddle.net/FNjJq/

Universality answered 22/12, 2010 at 0:11 Comment(2)
What you're doing there is just creating a new object. It's not the module pattern at all.Hectorhecuba
Afaik you are just creating a new object "this" inside the object "modulePattern". As a result you are not applying the pattern anymoreLillylillywhite

© 2022 - 2024 — McMap. All rights reserved.