Issue with variable scope in NodeJS, Express, Prototyping - javascript

File: MainApp.js
var reqHandler = reqire('HTTPRequestPostHandler')..
...
...
var httpRequestHandler = new reqHandler();
app.post('/', httpRequestHandler.handleRootPost);
File: HTTPRequestPostHandler.js
HTTPRequestPostHandler =function(){
this.someVar = value;
}
HTTPRequestPostHandler.prototype.handleRootPost{
console.log(this.someVar) //Error -> this.someVar is undefined.
}
I have these 2 files. The MainApp.js is where express is configured and various handlers for each endpoints e.g. '/'.
But when a post request occurs and the request handler (HTTPRequestPostHandler.prototype.handleRootPost) is invoked, I get a undefined error while accessing the variable this.someVar.
Why is this happening. What am I doing wrong here.

It's not a scope issue, it's a this issue.
Normally in JavaScript, this is set entirely by how a function is called, not where it's defined. So what's happening is you're passing your method in as a callback, but since it's not being called in a way that sets this to be your instance. (The next version of the specification, ES6, will have "arrow functions" that have this bound to them rather than being set by how they're called.)
The usual way that this gets set during a function call is when you call the function as part of an expression retrieving the function reference from an object, e.g.
foo.bar();
That calls bar with this set to foo. But this:
var f = foo.bar;
f();
...does not. this will be undefined (in strict mode) or the global object (in loose mode).
Other ways to set this are via Function#call and Function#apply, which let you call the function and explicitly say what this should be.
You can solve this with bind:
app.post('/', httpRequestHandler.handleRootPost.bind(httpRequestHandler));
bind returns a function that, when called, will call the original function with this set to what you pass in as the first argument.
More (on my blog):
Mythical methods
You must remember this

Related

How is the value of 'this' different in concrete implementation than on playground?

I am developing an app using a Node-Express stack using Socket.io and I found something weird. I have the following in one of my files:
const server = require('./server')
const io = require('socket.io').listen(server)
const Game = require('./service/game')
const game = new Game()
io.on('connection', (socket) => {
...
game.addPlayer(socket)
socket.on('increaseTime', game.increaseTime) // I know this is wrong
})
I have read about how you have to bind this if you want to use a callback as a handler, so in this specific case I know that on the commented line one of the solutions is the following to actually bind 'this' to the game instance, instead of the socket:
socket.on('increaseTime', game.increaseTime.bind(game))
What I do not understand is not this issue, but related to this. If I leave the line as is, so in the 'wrong' version I would still like to know how is the value of 'this' the socket. That is not what I would expect, because if I try to simulate this in a playground file, the value of this would be the the global object:
const socket = {
on(label, callback) {
callback()
},
}
const game = {
increaseTime() {
console.log(this)
}
}
socket.on('increaseTime', game.increaseTime) // global object
My guess is that the reason that it is the global object is that the value of this is lost, because when we use the 'this' keyword in a function inside of another function, it loses it's value and falls back to the global object (https://spin.atomicobject.com/2014/10/20/javascript-scope-closures/). My main question is how is it possible that the value of 'this' is the socket if I leave the 'wrong' implementation, how is it not the same as in the playground file?
I also tried instantiating dummy classes to have something resembling the actual implementation, but then the value of 'this' would be undefined, which I do not understand either (maybe it could be that the class keyword uses strict mode implicitely, so the fallback is not the global object, I don't know).
Any help would be greatly appreciated!
The value of this depends on how the function is called.
game.increaseTime.bind(game) creates a function which calls increaseTime with game as the this value.
callback() calls the function passed to the callback argument (and copied from game) without any explicit context (so this is the global object).
The code underlying socket.on clearly calls the function passed to it with the socket as the this value. There are several ways it could do that, you'd need to look at its source code to determine which one it uses.

When passing variable to function I get 'Invalid argument', but when I hard code it works in Apps Script

This is my test function:
var testFolderId = 'di98kjsdf9...';
function testGetFolder(testFolderId){
folder = DriveApp.getFolderById(testFolderId);
Logger.log("folders: " + folder);
}
It fails when I do this. The error says: INVALID ARGUMENT
However, if I hardcode the id into the 'DriveApp.getFolderById' function, it works.
Any explanation? This makes no sense to me.
When a function is called directly from the script editor/menu/button click/triggers, the following sequence of actions happens:
First, Entire script is loaded and All global statements are executed. This is equivalent to loading a web page with all your script in script tags: <script>...code.gs..</script>
The function you called is called. This is like adding callMyFunction() at the bottom of the already loaded script.
Except in case of triggers, The function you called is run without passing any arguments. Thus all arguments are undefined
Caution ⚠️: If the function is called by a trigger, the first parameter passed is usually the event object, while the rest of the parameters are undefined.
var testFolderId="1dhhddci6";
//When this function is called by IDE, it called without passing any arguments
function testGetFolder(testFolderId){//<=same as calling `testGetFolder()` or `testGetFolder(null)`
//testFolderId is declared in local scope , but is undefined
folder = DriveApp.getFolderById(testFolderId);//<= testFolderId is undefined
Workarounds:
Use default parameters:
//When this function is called by IDE, it called without passing any arguments
function testGetFolder(testFolderId="dhhddci6"){//<=same as calling `testGetFolder()`, but `testFolderId` is passed a value. Also same as calling `testGetFolder("dhhddci6")`
//testFolderId is declared in local scope and is defined(declared and intialized with a value)
folder = DriveApp.getFolderById(testFolderId);//<= testFolderId is "dhhddci6"
If global variables are used, Then the arguments should not be declared.
var testFolderId="1dhhddci6";
//When this function is called by IDE, it called without passing any arguments
function testGetFolder(){//<=same as calling `testGetFolder()`
//testFolderId is NOT declared in local scope, so variable is looked up in global scope(where it is defined)
folder = DriveApp.getFolderById(testFolderId);//<= testFolderId is "dhhddci6"
Further reading:
Scope
Closures
Default parameters
Hoisting
Event objects

Callback within a promise within a class?

I have a class that I use to load external resources via an XMLHttpRequest (this is for WebGL) so I'm loading models, shaders etc. My plan was to put a loading display up whilst it did all these requests and then when it's finally complete I want it to run a callback function from the original function that created it. However, I'm getting strange results when I try to run that call back (such as it has no access of any of the objects within the class that did the loading).
I can get around this problem by passing "this" into the loading class and then doing
self = this;
promise(self.callback());
but I'd much rather specify the function that I want it to callback to after its done the loading. Does anyone know if this can be done? My code looks like this:
Main Class
this.loadingClass = new LoadingClass(this.LoadingComplete, resources);
Main.prototype.LoadingComplete = function()
{
// Returns undefined if i specify the callback function instead of just "this"
console.log(this.loadingClass.anyOfTheMembersOfThisClass);
}
Loading Class
LoadingClass = function(callback, resources) {
..
Promise.all(resources).then(function(loadedResources)
{
..
callback();
});
}
When you pass the function object as
(this.LoadingComplete, resources)
the object to which it was bound, will not be passed. So, only the function object LoadingComplete is passed to LoadingClass and when it is invoked as
callback()
the this value will be undefined (in strict mode).
To fix this,
you need to bind the this object, like this
new LoadingClass(this.LoadingComplete.bind(this), resources)
if your environment supports ES2015's Arrow functions
new LoadingClass(() => this.LoadingComplete(), resources);
In both these cases, when the LoadingComplete is invoked from LoadingClass, the this will be retained.
You are detouching callback (read about "this") function from the root object, so of course it loses context. Specify bindingContext explicitly with Function.prototype.bind method:
this.loadingClass = new LoadingClass(this.LoadingComplete.bind(this), resources);

How the "this" affected in a method's method?

I am study the udacity's course and encounter a problem.
https://www.udacity.com/course/viewer#!/c-cs255/l-49464373/e-73862317/m-73162952
function xhrGet(reqUri,callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", reqUri, true);
xhr.onload = callback;
xhr.send();
}
var TILEDMapClass = Class.extend({
// Boolean flag we set once our map atlas
// has finished loading.
fullyLoaded: false,
//-----------------------------------------
// Load the json file at the url 'map' into
// memory. This is similar to the requests
// we've done in the past using
// XMLHttpRequests.
load: function (map) {
// Perform an XMLHttpRequest to grab the
// JSON file at url 'map'. We've provided
// the xhrGet function from the optional
// unit for you to use if you want.
//
// Once the XMLHttpRequest loads, set the
// 'fullyLoaded' flag to true.
//
// YOUR CODE HERE
xhrGet(map, function(){
this.fullyLoaded = true;
});
}
});
// We define a single global instance of our
// map for the rest of our game code to access.
var gMap = new TILEDMapClass();
the link says that it use gMap.load.apply(gMap, [jsonURL]);
http://forums.udacity.com/questions/100058023/scope-of-this#cs255
but I think that inspite the fact using the called mothod.(The load will belong to gMap)
But because
xhr.onload = function(){
this.fullyLoaded = true;
}
is a method belong to the xhr object,
and the this is inside an an anonymous function
the this should reference the xhr not gMap.
Why the this reference gMap?
this is funny within closures. You have to remember that the this keyword will usually refer to the owner of the method. Usually the caller (window for global functions) but when a method is called as a property of an object, this will refer to the object itself.
See this: "this refers to the parent object inside function code if the function is called as a property of the parent." Understanding this
The rules directly from Understanding this:
By default, this refers to the global object.
When a function is called as a property on a parent object, this
refers to the parent object inside that function.
When a function is called with the new operator, this refers to the
newly created object inside that function.
When a function is called using call or apply, this refers to the
first argument passed to call or apply. If the first argument is null
or not an object, this refers to the global object.
this doesn't necessarily mean the function or object it's being called on, if you're used to using jQuery and are confused by this, the jQuery methods actually set this on all of its functions for convenience by calling one of these two functions which set this to the caller:
call(object, arg0, arg1...);
apply(object, args[]);
So basically, unless the function is setting this by calling one of the above functions, it will be set to some outer function/object or window.
"this" in a javascript function has nothing to do with the object to which the function belongs, but what object it is executed against
Contrast with Java, where those are the same because a method is truly part of an object and cannot exist without one (not considering statics).
For example:
var blah = {
test: function () {
console.log('test');
}
};
var f = blah.test;
var bleh = {
test: blah.test
}
If I then make each of these three function calls, what is "this" pointing to in each call?
blah.test(); // this points to blah
f(); // this is null (or undefined, not sure which)
bleh.test(); // this is bleh
I can also use Function.call to call a function object in the context of any object: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
f.call(window); // this is window
Understanding "this" is difficult when working with callbacks because the callback function is usually invoked by some other library (like jquery for instance) and their API may or may not make a guarantee to what "this" refers to. What you can do as a work-around:
someAsyncFunction(function () {
bleh.test();
});
That will ensure the function you care about is called with a predictable "this" reference.

javascript class calling XMLHttpRequest internally, then handling onreadystatechange

this thing almost works:
function myClass(url) {
this.source = url;
this.rq = null;
this.someOtherProperty = "hello";
// open connection to the ajax server
this.start = function() {
if (window.XMLHttpRequest) {
this.rq = new XMLHttpRequest();
if (this.rq.overrideMimeType)
this.rq.overrideMimeType("text/xml");
} else
this.rq = new ActiveXObject("Microsoft.XMLHTTP");
try {
this.rq.onreadystatechange = connectionEvent;
this.rq.open("GET", this.source, true);
this.rq.send(null);
this.state = 1;
} catch (err) {
// some error handler here
}
}
function connectionEvent() {
alert("i'm here");
alert("this doesnt work: " + this.someOtherProperty);
}
} // myClass
so it's nothing more than having the XMLHttpRequest object as a member of my class, instead of globally defined, and invoking it in the traditional way. however, inside my connectionEvent callback function, the meaning of "this" is lost, even though the function itself is scoped inside myClass. i also made sure that the object that i instantiate from myClass is kept alive long enough (declared global in the script).
in all the examples of using javascript classes that i saw, "this" was still available inside the inner functions. for me, it is not, even if i take my function outside and make it a myClass.prototype.connectionEvent. what am i doing wrong? thank you.
The reason it's not working is that in Javascript, this is defined entirely by how a function is called, not where it's defined. This is different than some other languages.
To have this mean what you expect, you'd have to ensure that explicitly by "binding" it:
this.start = function() {
var self = this; // Set up something that survives into the closure
/* ...lots of stuff omitted... */
this.rq.onreadystatechange = function() {
// Call `connectionEvent`, setting `self` as `this` within the call
connnectionEvent.call(self);
};
There's more information about this management in this blog post, but basically: When a function is called without any particular effort made to set this, this within the function will always be the global object (window, on browsers). There are two ways to set this when making a call:
Using Function#call (or Function#apply) as I did above, passing in the object reference to use as this as the first parameter. That calls the function and sets this to whatever you passed in. The difference between #call and #apply is how you supply further arguments to pass into the function. With #call you supply them as further arguments to the #call call (e.g. func.call(thisArg, arg0, arg1, arg2)), whereas with #apply you supply them as an array in the second argument (func.apply(thisArg, [arg0, arg1, arg2])).
Using dotted notation: If you have an object that has a property with a function assigned to it (like your start property), calling it by using the object instance, a dot, and the property name (this.start() or foo.start(), etc.) will call the function and set this to the object instance within the call. So the dotted notation does two entirely distinct things: Looks up the property and finds a function as its value, and calls the function such that this is set to the object during the call. Literally it's like: var f = obj.func; f.call(obj).
Slightly off-topic, but: Barring a really good reason to, I wouldn't reinvent this wheel. There are lots of libraries out there to simply XHR calls. jQuery, Prototype, Closure, and nearly all the rest.

Categories