this context lost when passing a reference to a method [duplicate] - javascript

This question already has answers here:
Pass correct "this" context to setTimeout callback?
(6 answers)
Closed 6 years ago.
In this example
class Car {
describe() {
console.log("I have " + this.wheels);
}
testMe() {
setTimeout( this.describe, 1000);
}
constructor(wheels) {
this.wheels = wheels;
}
}
let myCar = new Car(4);
myCar.testMe(); // I have undefined
How come the expected value of this isn't passed inside the describe function ?
edit : Can you confirm that is setTimeout was an arrow function, I wouldn't get undefined ?

A bare function reference has no context, even if it was retrieved as a property of an object.
Within your testMe function you need either:
setTimeout(() => this.describe(), 1000);
or
setTimeout(this.describe.bind(this), 1000);
or
let self = this;
setTimeout(function() {
self.describe();
}, 1000);
That last one could be written as an arrow function, of course, but if you're doing that you might as well use the first version, with no local copy of this required.
Regarding your edit, it is possible to pass just this.describe by making describe an arrow function, assigned from inside the constructor, but note that this then means that every instance of the object would have its own copy of that function instead of there just being a single copy on the prototype of the class:
constructor(wheels) {
this.wheels = wheels;
this.describe = () => {
console.log("I have " + this.wheels);
}
}

Related

Calling class function from callback function calls in nodejs [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
I have this situation
class A {
a(params) {
//some code here
}
b(params) {
//some code here
}
c(params) {
this.a(function(data) {
console.log(this); // undefined
this.b(); // error no function b of undefined
})
}
}
I have tried binding this to 'a' using bind(this) but it says Cannot read property 'bind' of undefined or this is not defined. When I print this, I get class A. I want to call it inside 'a' function.
When you have defined a new function, the meaning of this has been changed inside it. You either need to use an arrow function:
this.a((data) => {
console.log(this); // class A
this.b();
})
or save the reference of this in a local variable:
var self = this;
this.a(function(data){
console.log(self); // class A
self.b();
})
Not sure at which point you are expecting the "b" method execution. I've added jsFiddle here: https://jsfiddle.net/k3jkobae/ and just saw that there was short correct answer while I was wrapping mine :) The arrow function is best suited.
class A {
a( callback ){
console.log('a');
callback();
}
b(params){
console.log('b');
}
c(params) {
this.a( () => this.b() );
}
}
const myClass = new A();
myClass.c();

What is "this" when in the callback of setTimeout? [duplicate]

This question already has answers here:
Pass correct "this" context to setTimeout callback?
(6 answers)
Closed 5 years ago.
Apologies for the newbie question, but consider this code
function Greeter( name) { this.name = name; }
Greeter.prototype.delayed_greet = function() {
setTimeout( function cb() {
console.log(' Hello ' + this.name);
}, 500);
};
Greeter.prototype.greet = function() {
console.log(' Hello ' + this.name);
}
const greeter = new Greeter(' World');
greeter.delayed_greet(); // will print "Hello undefined"
greeter.greet(); // will print "Hello World"
So in the delayed_greet method, what does this refer to when it's nested inside the setTimeout? It's obviously not referring to the greeter object otherwise it would work.
setTimeout is generally defined as window.setTimeout in browsers, and can be called as just setTimeout because it's available in the global scope.
That also means the context, and this value, is always window, unless another this value is explicitly set.
MDN says
Code executed by setTimeout() is called from an execution context
separate from the function from which setTimeout was called.
The usual rules for setting the this keyword for the called function
apply, and if you have not set this in the call or with bind, it
will default to the global (or window) object in non–strict mode, or
be undefined in strict mode.
It will not be the same as the this value for the function that
called setTimeout.
MDN also outlines a number of ways to solve the "this-problem" in setTimeout.
Personally I think I would just take the easy way out, and use a variable
Greeter.prototype.delayed_greet = function() {
var that = this;
setTimeout( function cb() {
console.log(' Hello ' + that.name);
}, 500);
};
Another option would be an arrow function, as they keep the surrounding context and don't create their own context.
var o = {
fn () {
setTimeout( () => { console.log(this) }, 500)
}
}
var o2 = {
fn () {
setTimeout( function() {
console.log(this === window)
}, 1000)
}
}
o.fn(); // fn() --- arrow function
o2.fn(); // true, is window --- regular function

No output from the object functions [duplicate]

This question already has answers here:
Referencing "this" inside setInterval/setTimeout within object prototype methods [duplicate]
(2 answers)
How to return value from an asynchronous callback function? [duplicate]
(3 answers)
Closed 5 years ago.
This question is from an written test for a company. It looks very confusing. I thought it will print whatever this.name is set to. Bu when I typed the code it shows nothing. I have little knowledge about closures and I think it is related to the problem. I want a little explanation here.
function dd(name) {
this.name = name;
this.go = function() {
setInterval(function() {
return this.name;
}, 2000)
}
}
var tt = new dd("corolla");
tt.go()
You can't get the return value from setInterval in this way. Try with a callback as in the following snippet
function dd(name)
{
this.name=name;
console.log( name );
var _this = this;
this.go=function(cb)
{
setInterval(function() {
cb(_this.name);
},1000)
}
}
var tt=new dd("corolla");
tt.go(function(ret) {
console.log( ret );
})
Also, please note that inside setInteval the value of this is not the same as in the otter function. That's why var _this=this;

difference between (callback) and (() => callback()) in typescript (angular2) [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
Normally I'd assign an alternative "self" reference when referring to "this" within setInterval. Is it possible to accomplish something similar within the context of a prototype method? The following code errors.
function Foo() {}
Foo.prototype = {
bar: function () {
this.baz();
},
baz: function () {
this.draw();
requestAnimFrame(this.baz);
}
};
Unlike in a language like Python, a Javascript method forgets it is a method after you extract it and pass it somewhere else. You can either
Wrap the method call inside an anonymous function
This way, accessing the baz property and calling it happen at the same time, which is necessary for the this to be set correctly inside the method call.
You will need to save the this from the outer function in a helper variable, since the inner function will refer to a different this object.
var that = this;
setInterval(function(){
return that.baz();
}, 1000);
Wrap the method call inside a fat arrow function
In Javascript implementations that implement the arrow functions feature, it is possible to write the above solution in a more concise manner by using the fat arrow syntax:
setInterval( () => this.baz(), 1000 );
Fat arrow anonymous functions preserve the this from the surrounding function so there is no need to use the var that = this trick. To see if you can use this feature, consult a compatibility table like this one.
Use a binding function
A final alternative is to use a function such as Function.prototype.bind or an equivalent from your favorite Javascript library.
setInterval( this.baz.bind(this), 1000 );
//dojo toolkit example:
setInterval( dojo.hitch(this, 'baz'), 100);
i made a proxy class :)
function callback_proxy(obj, obj_method_name)
{
instance_id = callback_proxy.instance_id++;
callback_proxy.instances[instance_id] = obj;
return eval('fn = function() { callback_proxy.instances['+instance_id+'].'+obj_method_name+'(); }');
}
callback_proxy.instance_id = 0;
callback_proxy.instances = new Array();
function Timer(left_time)
{
this.left_time = left_time; //second
this.timer_id;
this.update = function()
{
this.left_time -= 1;
if( this.left_time<=0 )
{
alert('fin!');
clearInterval(this.timer_id);
return;
}
}
this.timer_id = setInterval(callback_proxy(this, 'update'), 1000);
}
new Timer(10);

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

Categories