views:

290

answers:

4

After doing some reading about the Module Pattern, I've seen a few ways of returning the properties which you want to be public.

One of the most common ways is to declare your public properties and methods right inside of the "return" statement, apart from your private properties and methods. A similar way (the "Revealing" pattern) is to provide simply references to the properties and methods which you want to be public. Lastly, a third technique I saw was to create a new object inside your module function, to which you assign your new properties before returning said object. This was an interesting idea, but requires the creation of a new object.

So I was thinking, why not just use "this.propertyName" to assign your public properties and methods, and finally use "return this" at the end? This way seems much simpler to me, as you can create private properties and methods with the usual "var" or "function" syntax, or use the "this.propertyName" syntax to declare your public methods.

Here's the method I'm suggesting:

(function() {

var privateMethod = function () {
    alert('This is a private method.');
}

this.publicMethod = function () {
    alert('This is a public method.');
}

return this;

})();

Are there any pros/cons to using the method above? What about the others?

+3  A: 

Your function has no object context, so this references to the global window object in this case. Every property you assign to this automatically pollutes the global namespace.

(function() {
    console.log(this == window); // true

    this.publicMethod = function () {
        alert('This is a public method.');
    }

})();

console.log(publicMethod); // function()

You can explicitly pass it an object to tell which context to use.

var MYAPP = {};

(function() {
    // 'this' will now refer to 'MYAPP'
    this.publicMethod = function () {
        alert('This is a public method.');
    }
}).call(MYAPP);

console.log(publicMethod); // undefined
console.log(MYAPP.publichMethod); // function()

Which you can write in somewhat other style:

var MYAPP = (function(my) {
    var my;
    ⋮
    return my;
})(MYAPP);

And we arrived to an already discussed pattern. For further details, see Dustin's article on Scoping anonymous functions.

Török Gábor
Thanks a lot. I wasn't aware of the behavior of "this" within anonymous functions.
Rob
It's nothing to do with the function being anonymous. It's to do with how the function (any function, which could be created with a function declaration or a function expression) is called. If you call a function stored in a variable `f` (for example, defined by the function declaration `function f() {}` or via a function expression assigned to a variable: `var f = function() {};`) using the expression `f()`, `this` will always be the global object.
Tim Down
@Tim Down: thanks for your remark. I corrected my answer.
Török Gábor
+1  A: 

I would recommend the style where you add your public properties and methods to an anonymous object that you then return:

var myModule = (function() {
    function privateMethod() { ... }
    function publicMethod() { ... }

    return { publicMethod: publicMethod };
})();
Jakob Kruse
well, yes, except you're returning something that immediately gets thrown away.
Jason S
I'm curious as to what Jason means. What issues arise from using the anonymous object as a return? This seemed like the best of the techniques I came across, when using the module pattern.
Rob
I think Jason is referring to the code that was omitted or inferred, since we were discussing a Module pattern. I'll update my example.
Jakob Kruse
A: 

if you want to publish methods, then do something like:

var export = (function() {

var privateMethod = function () {
  alert('This is a private method.');
}
var export = {};

export.publicMethod = function () {
  alert('This is a public method.');
}

return export;

})();
Jason S
A: 

Another option is to avoid the this reference altogether. Define a function that creates and returns an anonymous object instead.

function makeThing(someAttribute) {
  var privateVariable = 42;

  function someMethod() {
    return privateVariable;
  }

  return {
    "publicMethodName": someMethod,
    "getAttribute": function() {
      return someAttribute;
    }
  };
}

var thing = makeThing(99);
thing.publicMethodName();
thing.getAttribute();
aekeus