This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
Take the following example;
class MyClass {
run() {
this.hello = 1;
co(function*() {
this.hello // this is now 'undefined'
})
}
}
new MyClass().run()
In ES5 I would normally assign this to another variable at the start of the function, such as var cls = this, but I would have hoped that ES6/ES7 would of solved this problem by now.
Is there a better way to do this?
You can use bind:
class MyClass {
run() {
this.hello = 1;
co(function*() {
this.hello // 1
}.bind(this));
}
}
new MyClass().run()
Related
I am using node 12 in my project. Back to 2 years ago, I remember I need to bind method for class instance method like below:
class Logger {
constructor () {
this.printName = this.printName.bind(this);
}
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
But recently I found I don't need to call bind in the constructor. Does the latest node version support auto-bind already?
The behavior hasn't changed. The situation in which you need to .bind is when the instance's printName method would otherwise get called without a calling context. For example:
class Logger {
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();
or with, instead of fn:
setTimeout(l.printName)
or with:
button.addEventListener('click', l.printName)`
In all of these situations, an error will be thrown if you don't use .bind, because the method gets called without a calling context - but the calling context of the Logger instance is needed for this to refer to the instance, so that this.print refers to the print method of the instance.
This sort of thing has always been true in Javascript. Nothing's changed in the past few years, except that it's now a bit easier to bind - you can use new class field syntax instead of having a constructor:
class Logger {
printName = (name = 'there') => {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();
I have a function that I need to pass to a class I have defined in nodeJs.
The use case scenario is I want to give the implementer of the class the control of what to do with the data received from createCall function. I don't mind if the method becomes a member function of the class. Any help would be appreciated.
//Function to pass. Defined by the person using the class in their project.
var someFunction = function(data){
console.log(data)
}
//And I have a class i.e. the library.
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall(){
var result = new Promise (function(resolve,reject) {
resolve(callApi());
});
//doesn't work. Keeps saying notificationHandler is not a function
result.then(function(resp) {
this.notificationHandler(resp);
}) ;
//I want to pass this resp back to the function I had passed in the
// constructor.
//How do I achieve this.
}
callApi(){ ...somecode... }
}
// The user creates an object of the class like this
var obj = new A("abc#gmail.com", someFunction);
obj.createCall(); // This call should execute the logic inside someFunction after the resp is received.
Arrow functions (if your Node version supports them) are convenient here:
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall() {
var result = new Promise(resolve => {
// we're fine here, `this` is the current A instance
resolve(this.callApi());
});
result.then(resp => {
this.notificationHandler(resp);
});
}
callApi() {
// Some code here...
}
}
Inside arrow functions, this refers to the context that defined such functions, in our case the current instance of A. The old school way (ECMA 5) would be:
createCall() {
// save current instance in a variable for further use
// inside callback functions
var self = this;
var result = new Promise(function(resolve) {
// here `this` is completely irrelevant;
// we need to use `self`
resolve(self.callApi());
});
result.then(function(resp) {
self.notificationHandler(resp);
});
}
Check here for details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
We have this code:
class Example {
constructor(num) {
this.a = num;
this.eventEmitter = null;
}
doSomething() {
// This doesn't work because 'this' will refer to the emitter.
this.a += 1;
}
registerEvents(eventEmitter){
this.eventEmitter = eventEmitter;
eventEmitter.on('event', this.doSomething);
}
}
and we want to bind it to an event emitter, like this:
function ExampleUser() {
const EventEmitter = require('events');
eventEmitter = new EventEmitter();
var reactor = new Example(1);
reactor.registerEvents(eventEmitter);
eventEmitter.emit('event');
}
The problem is, that when doSomething() is called, just like supposed, the this refers to the emitter, not to the Example object. Therefore, it cannot update this.a as we would like.
Help?
You need to bind your event listener to your Example instance:
registerEvents(eventEmitter){
this.eventEmitter = eventEmitter;
eventEmitter.on('event', this.doSomething.bind(this));
}
This question already has answers here:
ES6 arrow function lexical this in V8
(2 answers)
Closed 7 years ago.
I'm surprised this doesn't work. (I'm running iojs 2.3.0 with the --harmony_arrow_functions flag.)
class Foo {
constructor() { this.foo = "foo"; }
sayHi() { return (() => this.foo)(); }
}
f = new Foo();
f.sayHi // Cannot read property 'foo' of undefined.
I would have expected the arrow function to pick up the right value for this. Am I missing something?
I don't know the problem, but my version works fine for me:
class Foo {
constructor() {
this.foo = "foo";
}
sayHi() {
return (() => console.log(this.foo))();
}
}
const f = new Foo();
f.sayHi();
BTW: I am using babel
Your IIFE is creating a new scope. this is then referring to the scope of the IIFE where this.foo is undefined.
The way you'd get around this is by binding your IIFE.
class Foo {
constructor() {
this.foo = 'foo';
}
sayHi() {
return (() => {
return this.foo;
}.bind(this))();
}
}
let f = new Foo();
console.log(f.sayHi()); //foo
This is a bit foreign to me and I'm probably not understanding it correctly. This is what I have:
var imgModule = (function() {
var imgLocations = {};
var images = [];
imgLocations.setImage = function(img, location) {
imgLocations[img] = location;
}
imgLocations.getImg = function(img) {
return imgLocations[img];
}
imgLocations.setImageArray = function(img) {
images.push(img);
}
imgLocations.getImageArray = function() {
return images;
}
return imgLocations;
}());
I want to be able to access the imgLocations Object and images array from outside this function. The setting functions work, but
document.getElementById("but").onclick = function() {
console.log(imgModule.imgLocations.getImageArray());
console.log(imgModule.imgLocations.getImg(imgName));
}
Both return "undefined". How do I access these variables? And how can I improve this function? Please be patient with me and explain what I'm doing wrong :) I'm trying to learn it the right way instead of defining a global variable outside all functions.
The reason why this isn't working, is because your imgModule is returning the imgLocations object. That being the case, imgModule will actually be the imgLocations object. So you would access your methods like so:
imgModule.setImage()
imgModule.getImg()
imgModule.getImageArray()
imgModule.setImageArray()
And as #gillesc stated. If you are wanting to keep the current syntax of imgModule.imgLocations.getImg() then you could return the imgLocations like so
return {
imgLocations: imgLocations
}
doing so would allow you to add more functionality to your module
return {
imgLocations: imgLocations,
otherObject: otherObject
}
...
imgModule.otherObject.someFunctionCall();
The problem is you are returning the object created and are not setting it as a property of an object.
So in your case this is how it would work.
document.getElementById("but").onclick = function() {
console.log(imgModule.getImageArray());
console.log(imgModule.getImg(imgName));
}
What you need to do is return it like this
return {
imgLocations: imgLocations
}
If you want the API you are attending to create and still have access to the array which you can not do currently.
You don't access imgModule.imgLocations, since what you return is imgLocations, you should access them as:
document.getElementById("but").onclick = function() {
console.log(imgModule.getImageArray());
console.log(imgModule.getImg(imgName));
}
It seems you try to write module pattern.
For deep understanding, I recommend you following article:
The Module Pattern, by Addy Osmani
and pay attention to example with counter:
var testModule = (function () {
var counter = 0;
return {
incrementCounter: function () {
return counter++;
},
resetCounter: function () {
console.log( "counter value prior to reset: " + counter );
counter = 0;
}
};
})();
// Usage:
// Increment our counter
testModule.incrementCounter();
// Check the counter value and reset
// Outputs: counter value prior to reset: 1
testModule.resetCounter();