1

I have a problem understanding the scope of 'this' especially when nesting code

here is the example that I have a problem with

var callbacks = [];
MyClass.protoype.CallServer = function(name,index,callback)
{
   //some code
   callbacks[callback.length]  = callback;
   callserverfor(name,index, callbacks.length-1);

}

MyClass.prototype.ReceiveFromServer = function(callbackId,param)
{
   //somecode for simplicity let's say
   if(param)
    callbacks[callbackId].call(param);
  else
   callbacks[callbackId].call();
}

MyClass.prototype.Connect(Index,callback)
{
       CallServer('Connect' , Index, callback);
}

MyClass.prototype.Start= function(Index)
{

    this.Connect(Index,function()
    {
        this.ISConnected = true;

       //HERE this lost scope
        this.GetIdentified(Index, function( Identifier)
        { 
           alert('Identifier');

        });
    });
}

I even tried bind

MyClass.prototype.ReceiveFromServer = function(callbackId,param)
{
   //somecode for simplicity let's say
   if(param)
    callbacks[callbackId].call(param);
  else
   callbacks[callbackId].call();
}

MyClass.prototype.Connect(Index,callback)
{
       CallServer('Connect' , Index, callback);
}

MyClass.prototype.Start= function(Index)
{

    this.Connect(Index,function()
    {
        this.ISConnected = true;
        var GetIdentifier = this.GetIdentifier;
        GetIdentifier.bind(this);
       //HERE this lost scope
        this.GetIdentifier(Index, function( Identifier)
        { 
           alert('Identifier');

        });
    });
}

When I tried to use Me which point to this inside the code .. it worked .. Can I understand what is happening here as I don't get it

MyClass.prototype.ReceiveFromServer = function(callbackId,param)
{
   //somecode for simplicity let's say
   if(param)
    callbacks[callbackId].call(param);
  else
   callbacks[callbackId].call();
}

MyClass.prototype.Connect(Index,callback)
{
       CallServer('Connect' , Index, callback);
}

MyClass.prototype.Start= function(Index)
{
    var Me= this;

    this.Connect(Index,function()
    {
        Me.ISConnected = true;


       //HERE this lost scope
        Me.GetIdentifier(Index, function( Identifier)
        { 
           alert('Identifier');

        });
    });
}

Is there a better way of doing this or determining the scope of the callback ? any suggestions

Ibrahim Magdy
  • 343
  • 1
  • 3
  • 14
  • `this` in javascript works different than in other languages. Specifically, all functions have `this`, not just methods. So if you nest functions then the `this` inside the nested function comes from `function(){}` not from `MyClass`. Here's an answer that explains how `this` works: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628?s=1|3.8887#13441628 – slebetman Sep 28 '15 at 11:16

1 Answers1

1

Let me explain it with a little example:

var functions=[]; //a common array
functions.name="functions" //we add an attribute to that object

function generator(v) {
    var temp=v;
    return function () {
            console.log(this.name+temp);

    };
}

for (var i=0;i<5;i++) {
    functions[i]=generator(i); // here we add a bunch of functions to that object
}

If you execute functions[2]() you will obtain "functions2"in the console. Why? Because you are calling to a function that belongs to an object, (so that function is a method of that object) and that object is the "current context".

Then, if you execute something like this:

var f= functions[2];
f();

It will print "2" because f is executed as a "standalone" function, so the context is the "global context" and there is no "name" attribute created.

Be careful with callbacks, because they can be executed by other objects or functions. For example, if you set an event listener callback (you create a functions to be executed when user clicks somewhere), is the listener of that event who is going to execute it. So a classic trick is to create a variable as "me" "self" or "_this" to store the needed context in a clausure:

var myObj={ name:'my object'};
myObject= function () {
  var self=this; //here
  window.onclick=function(e) {
    console.log("I'm keeping a link to myObj: "+ self.name);
  }
}

If you want to select another context, you can also use f.call(context, first_parameter) or f.apply(context,[param0,param1...])

Pablo Lozano
  • 10,122
  • 2
  • 38
  • 59