Slavo
Slavo

Reputation: 15463

Javascript module pattern, scope and "this"

I'm trying to wrap my head around building a custom JavaScript library. I've read a lot about the module pattern, and also read Crockford's articles on private and public members. I know what is an immediately invoked function expression and why we do stuff like

var myLib = (function() {
}())

However, I'm still a little lost in some cases regarding scope and closures in general. The concrete problem I have is:

Why does the following example alert DOMWindow, rather than the myLib object? http://jsfiddle.net/slavo/xNJtW/1/

It would be great if you can explain what "this" refers to in all of the methods in that example and why.

Upvotes: 4

Views: 2241

Answers (4)

jbabey
jbabey

Reputation: 46647

In your linked fiddle, the "this" keyword is never changed by a "new" keyword or other context change, so it still refers to the global window object.

edit: clarification

Upvotes: -2

Diode
Diode

Reputation: 25135

Inside any function declared (anywhere) and invoked as follows this will be window object

function anyFunc(){
    alert(this);  // window object
}

anyFunc();


var anyFunc2 = function(){
    alert(this);  // window object
}

anyFunc2();

If you want to create private functions and access the instance of 'myObject' you can follow either of the following methods

One

module = (function () {

    var privateFunc = function() {
        alert(this);
    }

    var myObject = {
        publicMethod: function() {
            privateFunc.apply(this); // or privateFunc.call(this);
        }
    };

    return myObject;
}());


module.publicMethod();

Two

module = (function () {

    var _this; // proxy variable for instance

    var privateFunc = function() {
        alert(_this);
    }

    var myObject = {
        publicMethod: function() {
            privateFunc();
        }
    };
    _this = myObject;
    return myObject;
}());


module.publicMethod();

These are solutions to your issue. I would recommend using prototype based objects.

EDIT:

You can use the first method.

In fact here myObject is in the same scope as privateFunc and you can directly use it inside the function

 var privateFunc = function() {
     alert(myObject);
 }

The real scenario were you can use a proxy for this is shown below. You can use call also.

Module = function () {

    var _this; // proxy variable for instance

    var privateFunc = function() {
        alert(this + "," + _this);
    }

    this.publicMethod = function() {
        privateFunc(); // alerts [object Window],[object Object]
        privateFunc.call(this); // alerts [object Object],[object Object]
    }

    _this = this;
    return this;
};

var module = new Module();
module.publicMethod();

Upvotes: 4

Evert
Evert

Reputation: 8541

The thing to remember about the module pattern is that it runs once and completes. The methods that are still available to be called are the closures. At the time of creating module, "this" refered to the window and was replaced by its value.

Upvotes: -1

Thomas Thorogood
Thomas Thorogood

Reputation: 2357

You need to explicitly state that myPrivateMethod is a member of myLib:

function MyLib ()
{
    this._myPrivateField = "private";
    this._myPrivateMEthod = function ()
    { 
         alert(this); // Alerts MyLib function;
    }
}

var libObject = new MyLib();

Just remember that without using enclosure techniques, nothing in JavaScript is ever truly private!

A better way to do the above is like so:

function MyLib(instanceName)
{
    this.name = instanceName;
}

MyLib.prototype.myPrivateFunction()
{
    alert(this);
}

To call your method after that:

var libObject = new MyLib();
libObject.myPrivateMethod(); // Alerts info about libObject.

Upvotes: 0

Related Questions