Having a class Visual:
class Visual {
constructor() {...}
async fun1() {...}
async fun2() {...}
}
module.exports = Visual;
here everything works fine. However, I need to change it in order that fun1 depends on the output of fun2.
Firstly, I tried to use it the "normal" way but said the function is not defined.
async fun1() {
const result = await fun2();
...
}
So I tried another way, to move the function outside the class by exporting it.
class Visual {
constructor() {...}
async fun1() {
const result = await fun2();
...
}
}
module.exports = Visual;
module.exports = {
fun2: async function () {...}
};
The code inspector doesn't say anymore that fun2 is not defined but when a new Visual is created it says it is not a constructor.
const visual = new Visual();
Is it wrong the way it is exported? How can I solve it?
When you want to use one method in a class from another in that same class in javascript you'll have to prefix it with this.
so const result = await fun2(); becomse const result = await this.fun2();
This is the very important topic of the value of this inside a class.
One way to test this I believe is you could have done the following:
fun1() {
console.log(this);
}
Generally speaking, you want the value of this inside of a class to be equal to the instance of the class that you create because that is how you will refer to different instance variables and methods that are defined inside your class.
So I suggested the above, because the result should be an instance of the class and that would mean you can access the different instance variables defined on the class and the different methods as well, the latter being the issue you were having.
So the other way you could have tested in general, again removing the async/await syntax and just going with non-asynchronous functions is by attempting:
fun1() {
this.fun2();
}
fun2() {
console.log('its important that this works');
}
So if you see the value of this inside of fun1() not being what you expected, then you know you need to fix it up to invoke the different methods inside of your class and ensure the value of this is what you expect to be.
So I would recommend reading up on the value of this inside a class, in particular how you can determine the value of this inside a class and how you can change the value of this if its required.
Related
I have please encountered the following example in a book of a declaration of a class inside a function argument, even though I have searched thoroughly online, could not find an explanation, what it does, what is declared, what is passed into the function, and when should I use it if at all (perhaps its a bad practice ?).
Thank you for your help and guidance !
function f(parameter1) {
console.log(parameter1);
}
class ClassA {
}
f(class extends ClassA {
render() {
}
});
In javascript, class is just a syntax sugar for function, and just like function it's a first class value, which can be assigned, passed around etc.
let a = class {
foo() {
console.log('hey')
}
};
new a().foo()
//
function x(klass) {
new klass().bar()
}
x(class {
bar() {
console.log(2)
}
})
This is defining an anonymous class (in Java terminology... not sure if that is the correct name for JS). This example is pretty nonsensical. I could see it being used if the function f was accepting a class definition and then instantiated an object using it and proceeded to call methods on the object and perhaps return it. So it could be used in a general factory function.
I am having tough time figuring out when should we preferably use this keyword and when shouldn't we use it..
For example, I was earlier doing something like this.
let socket;
class something extends Component {
componentDidMount() {
socket = openSocket('https://coincap.io');
}
componentDidUpdate() {
socket.on('trades', (tradeMsg) => {
}
componentWillUnmount() {
this.socket.disconnect();
}
then someone re-structured my code did something like
class something extends Component {
componentDidMount() {
this.socket = openSocket('https://coincap.io');
}
componentDidUpdate() {
this.socket.on('trades', (tradeMsg) => {
}
componentWillUnmount() {
this.socket.disconnect();
}
[Question:] While, Both the code works and do the job, I am perplexed between understanding which methods should we use and why did he used this keyword?
You are dealing with ES6, which takes out a lot of ambiguity pertaining to the this keyword in the language.
Quite simply, this means (in the more traditional sense) the current scope; however, in JavaScript, this means the object calling the function as opposed to the current scope.
As mentioned previously, ES6 takes out a lot of complexity regarding variable hoisting and the likes.
Coming to your question, the reason it was refactored to this.something was because when your class is called (now, remember, JavaScript follows prototypal inheritance and is a first-class language; meaning that function prototypes are the class bases and functions can be passed as parameters) it will act like a function and the this keyword will refer to the object or the context where it was called.
If we have the following bit of code:
let foo = 'bar';
const fn = () => { console.log( this.foo ); }
fn();
The execution context would be window and the foo variable would be window.foo; hence, this.foo would translate to window.foo.
Similarly, your code will be transpiled something like:
var socket = new Socket();
function className() {}
className.prototype.someFunction = function() {
console.log( socket );
}
Here, the this keyword would make sure that the current context is used instead of local variables which you might use within your function.
I hope this makes it clear. Here is a great article to understand the this keyword! :)
The problem isn't the difference between this and a variable per se. It's that this refers to class instance and allows to have multiple class instances and thus multiple socket instances, while socket variable refers to specific socket instance and will be overridden in subsequent component instances.
The component will malfunction if there's more than one component instance at time, because socket variable refers to latest openSocket('https://coincap.io') result.
Also, this
let socket;
class something extends Component {
componentDidMount() {
socket = openSocket('https://coincap.io');
}
componentDidUpdate() {
socket.on('trades', (tradeMsg) => {
}
componentWillUnmount() {
this.socket.disconnect();
}
will result in error on component unmount because there's no this.socket.
Let's say I have a logging class called Logger.
let log = new Logger(...);
Is it possible to specify a magic method in that class to be executed when the class instance is invoked as function? For example
log(...)
In php implementing the __invoke() magic method of a class achieves the same thing.
function Logger() {
return function log(arg1, arg2) {
//#TODO: use the function's args
// or the arguments property to
// generate the log
console.log(log.arguments);
}
}
logger = new Logger();
logger('boom', 123, 'yolo');
This solution should to the trick you are looking for. How optimal it is or better ways of setting this up will probably be found in the comments below.
I find that it's very common to have code like (this is TypeScript, but the equivalent JS is fairly obvious and this is really a JS problem, although one that TS could solve):
class Foo {
someField;
someMethod() {
doSomethingTakingACallback(function() {
this.someField; // Fails because `this` is not the instance of `Foo`
});
}
}
The solution, of course, is to use Function.bind() like so:
someMethod() {
doSomethingTakingACallback(function() {
this.someField; // Works as expected
}.bind(this));
}
Now the problem is that I have callbacks that must access the object instance a lot (ie, I need to be calling bind(this) on many callbacks). I've now wasted more time on bugs resulting from this than I'd like to admit. Is there some alternative? Am I missing some easier way to do this? Is there any reason that this is the default behavior as opposed to the function that we get from calling bind(this)?
One solution I know of is to do something like var me = this and then call me.someField (etc). It's a little nicer looking when I have many callbacks or nested callbacks. Although then I lose out on the iconicness of this, which I feel makes it the most clear where the member is located (on the class that I'm writing).
Typescript and ES6/ES2015 both support the "fat arrow function" syntax, which allows you to use this the way you do in most other languages - to refer to the class instance object.
e.g.
someMethod() {
doSomethingTakingACallback(() => {
this.someField;
});
}
This compiles to the following code:
Foo.prototype.someMethod = function () {
var _this = this;
doSomethingTakingACallback(function () {
_this.someField;
});
};
ES6 Arrow functions keep the this of the surrounding scope and thus do not need binding.
ES7 will (possibly) have the :: bind operator
Assign this to another variable outside of your callback method and use that.
class Foo {
someField : any;
someMethod() {
var that = this;
doSomethingTakingACallback(function () {
// use that.someField;
});
}
}
Newbie to classes in javascript and can't solve this problem. Actually, anothermethod can return a callback to constructor and then I can can call onemethod from there, but maybe there's an easier way?
function sample() {} //constructor
sample.prototype = {
onemethod: function () {},
anothermethod: function () {
onemethod(); //Doesn't work
this.onemethod(); //Still the same
}
}
For it to work, you need to use it correctly. A constructor needs to be call via new.
var s = new sample();
s.anothermethod();
// identical to
sample.anothermethod.apply(s);
This way, this will represent s (and this the outer context, usually window).