In my Chrome App I need somehow Chrome to give the the reference to my object 'identity_service' in this variable when the callback is executed, but I don't know how.
This is my constructor:
function Identity(identity_host,identity_port) {
this.identity_host=identity_host;
this.identity_port=identity_port;
this.socket_fd=0;
chrome.sockets.tcp.create({}, this.socket_create_callback);
}
The function socket_create_callback is defined like this:
Identity.prototype.socket_create_callback=function(info) {
console.log('info='+info);
console.log('constructor name:'+this.constructor.name);
console.log('hostname='+this.identity_host);
this.socket_fd=info.socketId;
}
This is how I create it:
var identity_service=new Identity("localhost",4433);
Without object oriented programming Chrome calls the callback function with the parameter 'info' and it works fine. But when using OOP the 'this' variable doesn't hold the reference to my 'Identity' object otherwise the 'hostname' would not be undefined. This is what I get in the console log:
identity.js:21 info=[object Object]
identity.js:22 constructor name:Object
identity.js:23 hostname=undefined
With correct invocation of the callback the name of the csontructor would be 'Identity'. How can this be fixed?
The Chrome API call for creating a socket is this:
create
chrome.sockets.tcp.create( SocketProperties properties, function callback)
Creates a TCP socket.
Related
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.
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);
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
So, I've figured out how to call a method in JavaScript when you have the method name in a string e.g. strCallback = 'targetMethod'; window[strCallback]();, however, I get the following error message indicating that it can't find the method and after researching I'm still not sure why.
Calling the method by the actual name works, but not by using window[strCallback]();
Error:
Uncaught TypeError: Object [object global] has no method 'targetMethod'
Code:
function startMethod(strCallback) {
var results = '...';
// window[strCallback](results); // <-- Causes error
targetMethod(results); // <-- Works
}
function targetMethod(r) {
console.debug(r);
}
startMethod('targetMethod');
Thanks for any help.
From the discussion in comments it looks like the problem is the context in which the callback method is declared. If you use window[callback] it expects the callback to me declared in the global context, in your case it does not appear to be the case. It might be because you have declared everything inside a anonymous function/dom ready creating a closure context for the function.
As a solution I would recommend not to pass the callback as a function name string, instead pass it as a function reference.
So instead of calling startMethod('targetMethod');, you need to call startMethod(targetMethod); and invoke callback using strCallback() instead of window[strCallback](results);.
I solution we worked out in the comments was just a workaround where we forced the callback to the global scope which is not a recommended method
I have a namespace object on which I have defined some functions. One of the functions is used to create a websocket session to a remote server.
ns.Session = function(url, config, callback){
var ws = new WebSocket(url);
ws.onmessage = function (e){
if(login(e.data)){
// This is the point at which I need to pass back the session object to callback
callback(session):
}
}
....
}
In Javascript, as far as I know if someone invokes this function using ns.Session(....) then the this object will be ns. So, how do I get the instance of the "session" to send to the callback.
arguments.callee is deprecated as far as I know.
The whole reason I am doing it this way is that the session is not considered "usable" till the server confirms the login, so I don't want to prematurely return the function object before it is actually connected and logged in. Hence the use of a callback. If there is a better way to achieve this, I am open to that too.
Session has a bunch of other inner functions like addHandler, sendData etc which I have not shown here for sake of brevity.
You can use pointer to function like this:
ns.Session = function session(...) {
// 'session' here points to your function, so you do
callback(session); // like you wrote
callback(ns.Session); // same effect if you don't change ns and ns.Session pointers
}
Also, I don't see why you use the word "instance" in this case, because functions have only one instance. If you call it with the 'new' keyword, function creates new object from the function, and now there you can use "instance" word.