JavaScript Module Pattern - What about using "return this"?
Asked Answered
A

5

14

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?

Ariellearies answered 26/4, 2010 at 12:35 Comment(1)
Have you considered what exactly 'this' is? Where you are adding your publicMethod?Simpleton
C
30

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.

Chinoiserie answered 26/4, 2010 at 12:39 Comment(2)
Thanks a lot. I wasn't aware of the behavior of "this" within anonymous functions.Ariellearies
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.Plosive
S
4

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 };
})();
Simpleton answered 26/4, 2010 at 12:41 Comment(3)
well, yes, except you're returning something that immediately gets thrown away.Galvanic
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.Ariellearies
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.Simpleton
G
2

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;

})();
Galvanic answered 26/4, 2010 at 12:42 Comment(0)
U
2

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();
Uvula answered 26/4, 2010 at 19:6 Comment(0)
A
1

Revealing Module patterns:

var m1 = (function(){ return {method: mthod} })();
var m2 = new function Singleton(){ return {method: mthod} };
var m3 = ({}).prototype = {method: method};
var m4 = ({}).prototype = (function(){ ... })();
var m5 = (function(){}).prototype = {} || (function(){ ... })();

var m6 = (function(extendee){
    return extendee.prototype = {attr3: 'attr3'};
})({currentAttr1: 1, currentAttr2: 2});

Also, if you need method-chaining:

var m = (function(){}).prototype = (function(){
    var thus = m;  // this
    console.log('m this-------', thus);

    function fn(){
        console.log('fn', thus);
        return thus;
    }
    function f(){
        console.log('f', thus);
        return 'poop';
    }

    return {f: f, fn: fn};
})();

console.log('M:', m, 'm.fn', m.fn(), 'm.fn.f', m.fn().f());

There's also plenty more ways, and you can protagonize your modules as well.

Augustin answered 19/9, 2013 at 22:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.