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

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));
}

Related

JavaScript - error this.first() is not a function [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 5 years ago.
I'm just playing around and trying to figure out how the this object works and how do I pass scopes context with the bind function.
So far I got to this point (check code below), and found out that I can use bind with an object function in order to pass the scope of myObject to the object function run.
first question:
why do I need to use this.first() instead of first()?
Because otherwise its still using second's context.
myObject = {
first: function(){ console.log("myObject's first()")},
second: function(){
function first(){ console.log("second's first()")};
let run = function(){ this.first()}.bind(this);
run();
},
}
myObject.second()
Next, I wanted to take it to the next level and I nested another function within second (check code).
Second question:
From the code below i get the error Error: this.first is not a
function, and whether i invoke .bind(this) or not it gives the
same error, any clue why does this happen?
myObject = {
first: function(){ console.log("myObject's first()")},
second: function(){
function first(){ console.log("second's first()")};
function secondx2(){
function first(){ console.log("secondx2's first()")};
let run = function(){ this.first()}
run();
}
secondx2();
},
}
myObject.second()
Consider using arrows or try to store this in a global variable to access your functions
myObject = {
first: function(){ console.log("myObject's first()")},
second: function(){
var scope = this;
function first(){ console.log("second's first()")};
function secondx2(){
function first(){ console.log("secondx2's first()")};
let run1 = function(){ scope.first()} //myObject's first()
let run2 = function(){ first()}//secondx2's first()
run1();
run2();
}
secondx2();
},
}
myObject.second()

How do I reference class variables/methods from nested functions? [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
class Foo {
constructor() {
this.foobar = "foobar";
}
bar() {
let _this = this;
return function() {
try {
alert("Attempt 1: "+foobar);//ReferenceError: foobar is not defined
myMethod();
} catch(err) {console.log(err);}
try {
alert("Attempt 2: "+this.foobar);//TypeError: this is undefined
this.myMethod();
} catch(err) {console.log(err);}
try{
alert("Attempt 3: "+_this.foobar);//Works!
_this.myMethod();
} catch(err) {console.log(err);}
}();
}
myMethod() {
alert("myMethod()");
}
}
new Foo().bar();
The above example is very simplified - the anonymous function inside bar() was a jQuery call originally, but for the sake of the question I didn't include that.
Why don't attempts 1 and 2 work? Do I have to use the _this trick to reference class variables/methods? How do I reference class variables/methods from nested functions?
Are you familiar with how the this keyword works in JavaScript? It's value will depend on how the function is called, not in how it is defined. For example, if you do the following:
var dog = {
greeting:"woof",
talk:function (){
console.log(this.greeting);
}
};
var cat={
greeting:"meow",
talk:dog.talk
};
dog.talk();
cat.talk();
You will see that when the talk function is called as a method of an object, that object will be used as the value of this.
The same happens with ES6 classes, where class methods are still JavaScript functions and the rules for deciding the value of this still apply. If you want to avoid declaring an auxiliar variable, you should look into using bind:
var mammal = {
greeting:"<noise>",
getTalk:function (){
return function(){
console.log(this.greeting);
};
},
getTalkBinded:function (){
return (function(){
console.log(this.greeting)
}).bind(this);
}
};
var dog={
greeting:"woof",
talk:mammal.getTalk(),
talkBinded:mammal.getTalkBinded()
};
var cat={
greeting:"meow",
talk:mammal.getTalk(),
talkBinded:mammal.getTalkBinded()
};
dog.talk();
cat.talk();
dog.talkBinded();
cat.talkBinded();
You are returning self-execution function execution result and during that function execution this it global context(not your class object). to make it work use () => {}() arrow function call syntax, as it captures current context, or function() { }.bind(this)().
See this simple example,
function a(){
this.someProp = 5;
console.log(this);
var _this = this; //so we explicitly store the value of `this` to use in a nested function
return function(){
//value of `this` will change inside this function
this.anotherProp = 6;
console.log(this);
//to use the methods and props of original function use `_this`
console.log(_this)
}
}
var c = a.call({}) //prints {someProp: 5}
c.call({}) //prints {anotherProps: 6} {someProp: 5}

Method called by other method with setInterval can not access object property in js [duplicate]

This question already has an answer here:
passing this.method in setTimeout doesn't work?
(1 answer)
Closed 7 years ago.
I wrote a object constructor function with two methods, one of them calls the other via setInterval(functionName, interval), and the called function fails to get the objects properties.
I wrote a simple example on codepen: http://codepen.io/AttilaVM/pen/ZQPVEy
function Test(value) {
this.value = value
this.action = function testAction() {
console.log(this.value); // gives undefined!
}
this.play = function testPlay() {
setInterval(this.action, 500);
}
}
var test = new Test(20);
test.play();
If the method is called without setInterval it works as expected. Why is it different? How can the called method access the object's properties?
this refers to window as it is being call in setInterval(window.setInterval)
To pass the current context, Use .bind(this), The bind() method creates a new function that, when called, has its this keyword set to the provided value
function Test(value) {
this.value = value
this.action = function testAction() {
console.log(this.value);
}
this.play = function testPlay() {
setInterval(this.action.bind(this), 500);
}
}
var test = new Test(20);
test.play();

Simple Javascript object scope issue [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
Consider my following object and method:
function ModalPopupWindow() {
this.Modal = false;
function __InitModalPopUp(height, width, title) {
if(this.Modal != true){
divOverlay.onclick = function() { window.parent.HideModalWindow(); };
}
}
}
Whey I try to assess this.modal property inside the init function on a ModalPopupWindow object, 'this' is referencing to Window, not the object's property. How can I get that value?
There are several techniques, including a method named bind(). Another approach is to create a variable and bind it to the parent context before the function is called. I have seen people use a variable named underscore this (_this)
function ModalPopupWindow() {
//Capture the correct "this"
var _this = this;
this.Modal = false;
function __InitModalPopUp(height, width, title) {
//Use _this here
if(_this.Modal != true){
divOverlay.onclick = function() { window.parent.HideModalWindow(); };
}
}
}
I recommend this article if you want to learn more about how JavaScript works and how to use bind().
http://javascriptissexy.com/javascript-apply-call-and-bind-methods-are-essential-for-javascript-professionals/

js `this` context in a callback [duplicate]

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);
}
},

Categories