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

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

Related

Can't Access Class Property From Delegate Function [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 3 years ago.
Long-time .Net developer here, tasked with converting a bunch of old JS code to new ES6 JS modules. I'm trying to run the (you would think) simple code below, but when jumpToVideoNew is called, this.allowVidJump in the delegate function doesn't have access to the class property allowVidJump. I'm trying to set a simple timed delay so calling code can't hammer the jumpToVideoNew function repeatedly. I understand the concept that the variable loses scope, but I've tried setting _this = this; and using _this in the delegate as well with no success. Also tried passing a reference to the variable in to the function and accessing it that way, but also no luck. Spending 2 hours on something this simple is reminding me why I steer clear of javascript when possible.
export class WebUtility {
constructor() {
this.allowVideoJump = true;
this.delay = function () { this.allowVidJump = true; };
}
jumpToVideoNew() {
if (this.allowVideoJump) {
this.allowVideoJump = false;
setTimeout(this.delay, 1000);
}
}
}
Use an anonymous arrow function
The function keyword in JS creates a new scope as well as a new this (the function you just defined === this), so this.allowVidJump is essentially (function() {}).allowVidJump in that scope
Try something like this:
export class WebUtility {
constructor() {
this.allowVideoJump = true;
this.delay = () => { this.allowVidJump = true; }; // anonymous lambda
}
jumpToVideoNew() {
if (this.allowVideoJump) {
this.allowVideoJump = false;
setTimeout(this.delay, 1000);
}
}
}

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}

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

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

How to circumvent the ES6 Class scoping issue with 'this' key word [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
How do I write a named arrow function in ES2015?
(8 answers)
Closed 7 years ago.
For example in the Class constructor:
Socket.on('user:join', onUserJoin);
'onUserJoin' is declared as a method of the class but is being called by socket.io so the 'this' is not my Class. A way to resolve this is to use the '=>' function.
example:
Socket.on('user:join', (data)=>{
this.isOnline = true;
});
Now 'this' is my class, but how do I reference this anonymous function to unsubscribe ?
socket.removeListener('user:join', ????);
I did try this:
let self;
class RoomController {
constructor() {
self = this;
}
...
}
and reference the self in the methods but the self was being shared across sockets...
naming the anonymous function could solve it but I preferred for my case the bind option.
You can use Function.prototype.bind.
Socket.on('user:join', onUserJoin.bind(this));
This ensures that onUserJoin has the correct context, which will be the instance of your class.
You can always bind the arrow functions to the names.
For example,
class RoomController {
constructor() {
this.flag = true;
}
// Assign the arrow function to the name `setFlag`
setFlag = (v) => this.flag = v;
}
let r = new RoomController();
function tester(func) {
func(false);
console.log(r.flag);
// false
func(true);
console.log(r.flag);
// true
}
// Now you can pass the function around, `this` will still refer the object `r`
tester(r.setFlag);

How to call a function whose name is defined in a string? [duplicate]

This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 9 years ago.
I am passing function A's or B's name in a parameter based on the situation to another function C. How can I call it in function C?
if A is defined globally, then window["A"](). However, there's no need to do that in javascript. Just pass the function itself rather than its name:
function foo() {...}
// BAD
function callFunc(someName) { window[someName]() }
callFunc("foo")
// GOOD
function callFunc(someFunc) { someFunc() }
callFunc(foo)
Like this:
window[varName]()
assuming it is in global scope
If you have
function A() {}
function B() {}
then you can do
function C(parm) {
parm();
}
if you call it with C(A) or C(B)
DEMO
You could assign the functions to properties of an object. Then in your executing function reference the property by name given the parameter passed to the function.
var myFuncs = {
a: function(){
alert("Hello");
},
b: function(){
alert("Goodbye");
}
};
function execute(name){
myFuncs[name]();
}
execute("a");
execute("b");
Working Example http://jsfiddle.net/ud6BS/

Categories