js `this` context in a callback [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
Given class functions
game.PlayScreen = me.ScreenObject.extend({
onResetEvent: function() {
this.setAll(); //calls setAll(), which calls setGlobals()
this.saveNextLevelData(this.setAll);
},
saveNextLevelData : function (callback) {
$.get("./php/CRUD.php", {},
function (returned_data) {
callback(); //however, the callback of setAll throws
`undefined is not a function` error
}
},
setAll : function () {
log("setAll called");
this.setGlobals();
},
setGlobals : function () {
log("setGlobals called");
}
});
Basically, I'm confused on how this context is lost when you call a callback function.
In the above code,
Works: this.setAll() called directly from onResetEvent outputs "setAll called" and "setGlobals called"
Breaks: callback() calling this.setAll() from $.get outputs "setAll called" but this.setGlobals(); breaks... I think due to lost this context... It outputs Uncaught TypeError: undefined is not a function
I'm trying to follow the context of this when you call a callback function which contains a function belonging to the parent object (this, in this case). If I want to call this.setGlobals() from a callback of this.setAll(), where exactly do I need to do the bind?
Thanks

I think it is best to pass the context from the caller part, it can be done using $.proxy()/Function.bind() so
this.saveNextLevelData($.proxy(this.setAll, this));
Another solution will be is to pass the current object as the context to the callback from the ajax callback, the problem is by default this in the callback will refer to the ajax settings object. so
saveNextLevelData : function (callback) {
var self = this;
$.get("./php/CRUD.php", {},
function (returned_data) {
callback.call(self);
}
},

Related

Javascript why can one specify callback without parameters?

I originally come from the Java Programming language, and I was just wondering why it is possible in javascript to pass a callback function as a variable or plain object (without parameters) to another function, and then use this callback function inside of another function but this time with parameters to pass.
And how exactly is this callback returning my user object, as I did not specify a return function inside callback(user), or specify any function body at all for my callback. Is this done inside the setTimeout(()...) function as the timeoutHandler implementation is implicitly returning something?
var getUser = (id,callback) => {
var user = {
id: id,
name: 'Vikram'
};
setTimeout(() => {
callback(user);
},3000);
};
getUser(31, (userObject) => {
console.log(userObject);
});
I see two questions here:
why it is possible in javascript to pass a callback function as a variable or plain object (without parameters) to another function.
Because functions are first-class objects, we can pass a function as an argument in another function and later execute that passed-in function or even return it to be executed later.
Read more here: https://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/
Below shows functions are just objects as well:
function hello() {
return 'hello';
}
hello.other = 'world';
console.log(hello() + ', ' + hello.other);
how exactly is this callback returning my user object, as I did not specify a return function inside callback(user), or specify any function body at all for my callback.
setTimeout(()...) function is not implicitly returning anything, it just registers a function, that would execute later. When the function registered by the setTimeout triggers, it invokes the callback(user) and that resolves getUser registered function which logs to the console. Remember callbacks are asynchronous.
Functions have implicit returns if not specified, which returns undefined, meaning you did not explicitly return.
Below shows an example:
function hello() {
console.log('Hello, World');
}
console.log(hello()); // undefined.
function hi() {
return 'Hi, World';
}
console.log(hi()); // Hi, World.
The function i.e callback is passed as reference here. So you can pass it as much you want, when you call it then you can pass on the arguments and it will refer to original function.
And also it's not returning the user object, it's just consoling out the user object. As you have not used any return it will return undefined. Try consoling the callback fn return out.
var getUser = (id,callback) => {
var user = {
id: id,
name: 'Vikram'
};
setTimeout(() => {
console.log(callback(user), 'return value of callback');
},3000);
};
In javascript function is a object.
It behaves like function only with ()
So you can pass function to another function or variable as value.
Some functions in javascript are asynchronous.
setTimeout is such async function. It means callback function will be run after a time.
What's happening:
//assign anonymous function to variable
// until function without () it only a object
var getUser = (id,callback) => {
//set up params
var user = {
id: id,
name: 'Vikram'
};
// setup asynchronous function setTimeout
setTimeout(() => {
// run callback with params when time would done
callback(user);
},3000);
};
// call function which contains in getUser-variable and pass 2 params: int and callback-function
getUser(31, (userObject) => {
console.log(userObject);
});

Why is "this" pointing to the "window Object" in the callback function?

var callBackFunc = {
value : "CallBackValue",
getValue : function(callback) {
callback();
}
}
var TestingFunc = {
value : "TestingValue",
alertValue : function() {
console.log(this);
}
}
$(function() {
callBackFunc.getValue(TestingFunc.alertValue);
});
I don't want answers to be able to use it properly, but I wonder why "this" points to Window Objects. Plz... Help me!!
because arguments passed by value which means
callBackFunc.getValue(TestingFunc.alertValue);
equals to
callBackFunc.getValue(function() {
console.log(this);
});
so ,callback() works
(function() {
console.log(this);
})()
so ,you get window.
If arguments passed by name ,in this case name is TestingFunc.alertValue,then you will get what you want like :
callback() equals to TestingFunc.alertValue()
However,js works by value not name
The plain callback function reference is passed as a parameter to the callBackFunc.getValue, so there is no current this context will be formed with the plain function and the default this leads to the global object (window).
In order to form the context, we can use call, bind, apply methods.

Javascript handler reference to environment it was defined in [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
In one of my classes, a method performs AJAX requests. In the callback function of a request, I need to call another method of my object, using this. But this does not refer to my object in this context, so I don't know how to do... Is it only possible ?
To clarify, please consider the following code :
function MyClass(arg) {
this.foo = arg;
}
MyClass.prototype = {
myMethod: function() {
console.log("I am myMethod");
},
myGet: function (){
$.get("http://example.iana.org/",function(data){
this.myMethod(); // does not work, because 'this' does not refer to my object
});
}
}
var obj = new MyClass("Javascript is complicated");
obj.myGet();
You can define a variable to store this in the closure :
myGet: function (){
var _this = this;
$.get("http://example.iana.org/",function(data){
_this.myMethod();
});
}
or use $.proxy :
myGet: function (){
$.get("http://example.iana.org/", $.proxy(function(data){
this.myMethod();
}, this));
}
or, if you don't do more than calling myMethod in the callback :
myGet: function (){
$.get("http://example.iana.org/", $.proxy(this.myMethod, this));
}
In modern browsers you can also use bind. When I don't have to be compatible with IE8 I do
myGet: function (){
$.get("http://example.iana.org/", this.myMethod.bind(this));
}

Supplying a callback and the context within which it is to be run [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 9 years ago.
myFn performs an async task and calls the callback on success
SearchController.prototype.show = function (query) {
this.searchService.myFn(arg1, this.myCallback); //I want to maintain this `this`
};
SearchController.prototype.myCallback = function (err, result) {
if(err) {
this.onError(err);
return;
}
this.onSuccess(result);
}
SearchController.prototype.onSuccess = function() {...)
SearchController.prototype.onError = function() {...)
Clearly the meaning of this is lost in the callback. How can I maintain this to be the this from the invocation of myFn?
It should be the responsibility of the myFn function to accept a context as parameter and then use it, or rewrite the method signature and wrap your call in an anonymous function that use call Function.prototype.call:
SearchController.prototype.show = function (query)
{
var __this = this;
this.searchService.myFn(function (){ __this.myCallback.call(__this, arg1); });
};
Here is how I would like to see myFn:
SearchController.prototype.myFn = function (arg, callback, context)
{
// Do work.. when finished:
callback.call(context, arg);
};
If you're having multiple args you want to apply, then use Function.prototype.apply.

Function as a Parameter that Returns an Anonymous Object

I see a lot of javascript code that passes a function as a parameter that returns an anonymous object.
myFunction(function() {
return {
foo: 'bar'
};
});
What is the advantage or the purpose of using this instead of simply passing directly an anonymous object?
myFunction({
foo: 'bar'
});
The difference is that if you alter the argument passed in your second code snippet, there is no way to get the original argument again.
If you pass an function instead you can call the function more than once and get always the same argument back. (if the function is implemented this way)
Furthermore if you use a function you can do additional stuff like logging how often your function / argument was called or so on. So using a function adds more flexibility for the user of the function.
For the developer of the function on the other hand accepting a function as argument can cause the tiny problem that a function doesn´t have to return the same value every time you call it - myFunc() == myFunc() COULD return false, therefore i would not recommend handing over a function if it is supposed to JUST return an argument.
Backbone uses have a lot of places where they will initialize the function if passed to get the value, eg.
Backbone.Model.extend({
url: function() { return 'myurl.aspx'; }
});
// VS
Backbone.Model.extend({
url: 'myurl.aspx'
});
This is clever if you will have to make some calculation / run some conditions before you'ill know that the url is.
Backbone.Model.extend({
url: function() {
if ( this.get('name') ) {
return 'service1.aspx';
}
else {
return 'service2.aspx';
}
}
});
Your first example sends an anonymous function as the first argument to myFunction while the second example sends an object as the first argument.
myFunction(function() {
return {
foo: 'bar'
};
}); // function() {...}
myFunction({
foo: 'bar'
}); // {foo: 'bar'}
function myFunction(what) {
console.log(what);
}
If you are talking about closures, the main difference is that you can have private variables inside closures:
var setGet = (function() {
var v = null;
return {
get: function() { return v; },
get: function(val) { v=val; },
};
});
// VS:
var setGet = {
v: null,
get: function() { return this.v; },
get: function(val) { this.v; },
};
In the first example you can't access the variable v without using .get/.set on setGet while in the 2. example i can simple change it by setting setGet.v = 'new_val';
In the first example You are passing a callback function.
When we pass a callback function as an argument to another function,
we are only passing the function definition. We are not executing the function
in the parameter.
And since the containing function has the callback function in its parameter as a function definition, it can execute the callback anytime. This allows us to execute the callback functions at any point in the containing function.
A simple example for this is jQuery click binding :
/The anonymous function is not being executed there in the parameter.
//The anonymous function is a callback function
$("#btn_1").click(function() {
alert("Btn 1 Clicked");
});
But in the second example you are simply passing an object to the called function.
Use this link to get more details about Callback functions. Enjoy :)
I think, it really depends where you saw the code being used.
In this case, myFunction seems to require you to pass a function rather than an Object.
But in general, Consider this
myFunction(function() {
var a = "bar";
return {
foo: a
};
});
and this:
var a = "bar"
myFunction({
foo: a
});
In the second case, anyone outside is able to access a. But in first case, a becomes similar to a private variable which is exposed as public by the function. So you might observe this in places where people wish to follow OOP concepts in the otherwise classless JS.
Another case is where you require a callback function or some function that is to be called later. So if the data is to be preserved until a certain something is over you can make it available as the return value of a function, rather than storing it globally...

Categories