Your Universal Remote Control Center
RemoteCentral.com
Philips Pronto Professional Forum - View Post
Up level
Up level
The following page was printed from RemoteCentral.com:

Login:
Pass:
 
 

Original thread:
Post 2 made on Friday May 20, 2011 at 21:44
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,996
Below will explain why the use of 'this' inside closure functions intended for system-level callbacks does contain the value of the outer object as one might think.

The value of 'this' depends on how you are calling the function including the context in which the function is being called (system callback). Note that in serial and socket callbacks, the keyword 'this' is set up to be the serial port or socket that is issuing the callback. In the case of scheduleAfter callbacks, 'this' is not your 'Device' instance, but rather the Activity instance. i.e. It will be the value of CF.activity().

If you were to change the code to:

var proj = new Device();
proj.pollPower();

You'd see the result you expect. However, your closure function is called from a different context when scheduleAfter() is used.


To overcome this, you can make one very small tweak to solve your issue.

function Device()
{
// you should define the object instance in a variable that can be referenced throughout other functions and not use 'this' keyword.
var target = this;
this.sendCommand = function(s)
{
System.print("command: " + s);
};

this.pollPower = function()
{
// note that we do not use 'this' here because the function, even though it is a member field of your 'Device' instance, is still called as a non-object-based JS function and 'this' will be the CF.activity() scope.
target.sendCommand("pollPower");
};
}

var proj = new Device();
scheduleAfter(10, proj.pollPower);

The above code, after 10 or so miliseconds should issue the System.print as you expect.

Now, you can resort to something else as well and allows you to define the function any place (as standalone function outide of Device, if you like).
What you want to do is to pass value of 'proj' as a single parameter to be used with the call to the function at a later time as in:

function Device()
{
this.sendCommand = function(s)
{
System.print("command: " + s);
};

this.pollPower = function(whichDevice)
{
// note that we do not use 'this' here because the function, even though it is a member field of your 'Device' instance, is still called as a non-object-based JS function and 'this' will be the CF.activity() scope.
whichDevice.sendCommand("pollPower");
};
}

var proj = new Device();
scheduleAfter(10, proj.pollPower, proj);

Note that when the pollPower function is called, it will receive this single parameter which you use as a substitution for 'this'.

Hopefully now, you can see why scheduleAfter function was designed to support that 3rd parameter. It specifically was added to help overcome issues with 'this' and scope changes if a function is called via a callback vs through a member field.

Background on why things are the way they are!!!

Note that with this line:

scheduleAfter(10, proj.pollPower);

you are simply providing the function to be called, (proj.pollPower) and not the scope in which is should be called.

The behind-the-scenes implementation of scheduleAfter use the equivalent of the Javascript Function.call or Function.exec methods to call your function.

If you look at a Javascript reference, you will see that either of these functions requires that the first parameter be the 'scope' to which the call applies. In the case of a TCPSocket, UDPSocket, Serial, Input, Activity, or a Widget, the value supplied for the first parameter is the ProntoScript object for which the callback applies.

My final note on this subject is a reminder that when the repeat interval of a Page or a Widget is specified and causes script to be executed, the keyword 'this' is the value of the Prontoscript object for which your code is applied (with the values being those returned by a call to CF.page() or CF.widget()/GUI.widget() respectively).

If you still need more information or would like to read more about this topic, you can see both the chapter/section in the Dev Guide on scopes and also see the Javascript book by David Flanagan.


If you don't mind, would you please consider editing the above post so that the subject line reads something like "Inside system callbacks, keyword 'this' might not be what you expect."

Best of luck.

Lyndel

Last edited by Lyndel McGee on May 20, 2011 21:53.
Lyndel McGee
Philips Pronto Addict/Beta Tester


Hosting Services by ipHouse