Using es6 arrow functions inside class [duplicate] - javascript

This question already has answers here:
How to use arrow functions (public class fields) as class methods?
(4 answers)
Closed 8 months ago.
When i change a function draw(){ //} to draw = () => { // }
I am getting an error like "Uncaught SyntaxError: Unexpected token =".
What may be the reason?

First of all, you probably shouldn't do that. Why? Well, because arrow functions are not semantically the same as regular functions.
If you register the functions as this.draw = () => {//}, then every instance of your class* will have a duplicate definition of that function which is a waste of space and a misuse of some core language features such as prototype inheritance.
draw() on the other hand registers that function on the prototype so that definition of the draw function can be shared between all instances and even changed dynamically for ALL instances at the same time.

In your constructor you can have this.draw = () => {//} but there isn't really much point in doing this. draw(){//} should be fine for anything you want.
Below, in my example, I've shown both use cases as you can see nothing is saved by using an arrow function.
class StandardFunction {
draw() {
console.log('StandardFunction: you called draw')
}
}
class ArrowFunction {
constructor() {
this.draw = () => {
console.log('ArrowFunction: you called draw')
}
}
}
const test1 = new StandardFunction();
const test2 = new ArrowFunction();
test1.draw();
test2.draw();
I hope you find this helpful

You will need to use babel's Class properties transform, which will transpile:
class Picture {
draw = () => {
console.log('drawing')
}
}
into:
class Picture {
constructor() {
this.draw = () => {
console.log('drawing');
};
}
}
You can try it in this repl (make sure to enable the class properties transform plugin)

Related

JavaScript class property cannot be found [duplicate]

This question already has answers here:
Javascript: Do I need to put this.var for every variable in an object?
(6 answers)
Closed 6 months ago.
I have this snippet of code. I am very new to JavaScript, and I have an error in:
class X {
constructor() {
this.pick = -1;
this.isClosed = false;
this.pline = [];
}
add(mx, my) {
pline.push(Point(mx,my));
}
draw() {
beginShape();
for (let i = 0; i < pline.length; i++) {
p = pline[i];
vertex( p.x, p.y );
}
... //ignore the rest for now
the issue I am getting is: X, line 14:ReferenceError: Can't find variable: pline
I am a little confused because I am initializing it as a class property, so I am not sure why it cannot be found in the draw function. Any help is highly appreciated.
This is because you have scoped pline to this, so it must be this.pline.push.
Also, if you want to use this scope, it's best to use arrow function methods to maintain the scope. Example:
class clazz{
constructor() {
this.something = 1;
}
add = () => {
console.log(this.something);
};
}
pline refers to a variable (either local or global), not a property. If you want to access a property, then you must use this.pline. Although variables and properties seem the same, under the hood they are fairly different because of how JavaScript classes work (which is quite different from most languages).
in your add() function you are referring to "pline.push()", you need to use this.pline.push()

Should we add methods only to the prototypes of our objects?

I'm currently studying Javascript and saw that we can define members of an object in its prototype instead of in the object's constructor since it makes the objects lighter because they don't carry the method code in every instance.
I can see how variables can work badly if all objects of this constructor point to the same variable field, but methods shouldn't change too much or at all, so its not a problem to share them.
Is there a reason not to define methods on the prototype rather than the object's constructor?
One reason why one might prefer putting methods on the instance itself would be to ensure the correct this context while adding a method concisely. Getting this to work properly is a very common problem in JavaScript.
For example:
class Foo {
i = 0;
clickHandler = () => console.log(this.i++);
}
const f = new Foo();
window.onclick = f.clickHandler;
This is a common pattern with class components in React. If one put the method on the prototype instead, it could sometimes get a bit uglier:
class Foo {
i = 0;
clickHandler() {
console.log(this.i++);
}
}
const f = new Foo();
window.onclick = () => f.clickHandler();
Another common way of dealing with this is to move a bound method from the prototype to the instance in the constructor:
class Foo {
i = 0;
constructor() {
this.clickHandler = this.clickHandler.bind(this);
}
clickHandler() {
console.log(this.i++);
}
}
const f = new Foo();
window.onclick = () => f.clickHandler();
Is that reason to prefer one over the other? That's up to you, but its one arguable advantage to keep in mind.
Just an idea from me - there is a way of dealing with the "proper" execution context of e.g. click handlers on prototype level as well. Consider the following example:
class AbstractClickHandler {
// the "proper" this is ensured via closure over the actual implementation
clickHandler() {
return (...args) => {
this.handleClick.apply(this, args)
}
}
// no-op in base class
handleClick() {
}
}
class ClickHandler extends AbstractClickHandler {
constructor(data) {
super()
this.data = data
}
// actual implementation of the handler logic
handleClick(arg1, arg2) {
console.log(`Click handled with data ${this.data} and arguments ${arg1}, ${arg2}`)
}
}
const instance = new ClickHandler(42)
const handler = instance.clickHandler()
handler.call(null, 'one', 'two')
This way, there is no need to define a bound handler in every concerned constructor.

ES6 functions, arrow functions and 'this' in an ES6 class [duplicate]

This question already has answers here:
Should I write methods as arrow functions in Angular's class
(3 answers)
Arrow vs classic method in ES6 class
(1 answer)
Closed 5 years ago.
class App extends Component {
constructor(props) {
...
}
onChange = (e) => this.setState({term: e.target.value})
onSubmit(e){
e.preventDefault();
const api_key = "C1hha1quJAQZf2JUlK";
const url = `http://api.giphy.com/v1/gifs/search?q=${this.state.term}&api_key=${api_key}`;
}
render() {
return (
<div>
<form onSubmit={this.onSubmit}>
<input value={this.state.term} onChange={this.onChange}/>
<button>Search!</button>
</form>
</div>
);
}
}
What is the difference between the two type of functions declared in the class (onChange and onSubmit). I get an error on referencing this.sate in const url if I declare it as an ES6 class method but changing it to arrow function fixes it.
I want to know how exactly 'this' is handled in both the cases
Also, how do I do it the other way? Say, if I want to use the same onSubmit function (ES6 class method) but want to handle this when I call it (in the form element), how do I do it ?
Using this.onSubmit.bind(this) ?
It's important to know that this syntax:
class A {
method = () => {}
}
is just syntactic sugar for creating an instance method in the class constructor:
class A {
constructor() {
this.method = () => {}
}
}
Note: This syntax is not an official part of the JavaScript language yet (currently in stage 3) so you must use a transpiler like Babel to handle it.
The value of this within method is the class A because that is what this points to in the constructor (since arrow functions inherit the context from the scope they are defined in):
class A {
constructor() {
this.method = () => this;
}
}
const instance = new A();
console.log(instance.method() === instance); // true
Defining a regular (non-arrow function) method on the class creates a method on the class prototype (not instance) but sets no rules on what this will be (since this is dynamic in JS and depends on how a function is called, not how it's defined).
class A {
method() {}
}
console.log(new A().method === A.prototype.method); // true
If methods defined in either of these ways are called on the class instance (via the .), as per the rule of how this is bound when a function is called as a method of an object, this will point to the class instance in both cases:
class A {
constructor() {
this.methodOnInstance = () => this;
}
methodOnPrototype() { return this; }
}
const instance = new A();
console.log(
instance.methodOnInstance() === instance.methodOnPrototype(), // true
instance.methodOnPrototype() === instance // true
);
One major difference between the two method declarations above is that the instance method has this always fixed to the class instance while the class (prototype) method does not (we can change it by using Function.prototype.apply or Function.prototype.call)
class A {
constructor() {
this.methodOnInstance = () => this;
}
methodOnPrototype() { return this; }
}
const instance = new A();
console.log(
instance.methodOnInstance() === instance.methodOnPrototype(), // true
instance.methodOnPrototype.call('new this') === 'new this' // true
);
A common occurrence where the this changes is within an event handler, where the event handler calls the function passed into it and binds the context to the element on which the event happened (so overrides the value of this to be the element that was clicked or whatever the event was)
This happens in React as well for all (synthetic) DOM event handlers.
Therefore, if we want our method's context to always point to the instance of the React component, we can use the instance method.
Another way of restricting the context but not using the special instance method syntax that requires Babel is to directly create an instance method ourselves by creating a new function from the class (prototype) method with a bound context (using Function.prototype.bind):
class A {
constructor() {
this.methodOnInstance = this.methodOnPrototype.bind(this);
}
methodOnPrototype() { return this; }
}
const instance = new A();
console.log(
instance.methodOnInstance() === instance.methodOnPrototype(), // true
instance.methodOnPrototype() === instance // true
);
This allows us to arrive to the same result as using the special instance method syntax but with the currently available tools (ES2017 and under).
If for some reason we want a method that is always bound to something that is not an instance of the class, we can do that as well:
class A {
constructor() {
this.method = this.method.bind(console);
}
method() { return this; }
}
const instance = new A();
console.log(
instance.method() === console // true
);
An arrow function expression has a shorter syntax than a function
expression and does not have its own this, arguments, super, or
new.target. These function expressions are best suited for non-method
functions, and they cannot be used as constructors.
Arrow Functions lexically bind their context so this actually refers to the originating context.
In ES3/4 functions declaration you can use this by storing in some other variable.
const that = this;
onSubmit(e){
e.preventDefault();
const api_key = "***************";
const url = `http://api.giphy.com/v1/gifs/search?q=${that.state.term}&api_key=${api_key}`;
}
Also, how do I do it the other way? Say, if I want to use the same onSubmit function (ES6 class method) but want to handle this when I call it (in the form element), how do I do it ?
Using this.onSubmit.bind(this) ?
Yes you must bind the method to the component in the constructor. It's because the arrow functions get automatically binded to the class therefore the scope of this is set in the method. While onSubmit is a regular function that is not yet binded therefore the this inside the method will reference the function and not the component.
You need to use bind in your class's constructor with the ES6 class method. In essence, arrow functions do this for you automatically.
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
The more important thing to note here is that I believe the arrow function here will be created on each instance of the class, where the ES6 class method will be made part of the class's prototype and shared amongst all instances.
The key difference is that in ES5 we don't have auto binding which means you have to bind your event handler function manually in order to play with state or props inside the function in react. But in ES6 it does auto binding. That's the key difference
ES5: you have to bind onSubmit preferably in constructor
//is valid
this.onSubmit = this.onSubmit.bind(this);
onSubmit(e){
e.preventDefault();
const api_key = "C1hha1quJAQZf2JUlK";
const url = `http://api.giphy.com/v1/gifs/search?q=${this.state.term}&api_key=${api_key}`;
}
ES6:
The below is valid because it does auto binding.
onChange = (e) => this.setState({term: e.target.value})

Why can't I access `this` within an arrow function? [duplicate]

This question already has answers here:
What does "this" refer to in arrow functions in ES6?
(10 answers)
Closed 7 years ago.
This code below should work as expected, and log "meow", here an example.
function Cat () {
this.animalNoise = 'meow'
}
Cat.prototype.sound = () => {
console.log(this.animalNoise)
}
let cat = new Cat()
cat.sound()
It doesn't work, this error appears TypeError: Cannot read property 'animalNoise' of undefined and when you convert the arrow function to an actual function declaration it works. It seems like with the arrow function, I no longer have access to this. What's going on here?
To be clear, the above code does not work where the following does, and I'm very curious why.
function Cat () {
this.animalNoise = 'meow'
}
Cat.prototype.sound = function() {
console.log(this.animalNoise)
}
let cat = new Cat()
cat.sound()
Arrow functions perform lexical binding and uses the surrounding scope as the scope of this. For example, imagine (for some weird reason) you define Cat inside of a Dog constructor.
function Dog() {
// do dog like things
function Cat() { ... }
Cat.prototype.sound = () => {
// this == instance of Dog!
};
}
So whatever the surrounding scope is becomes the scope of an arrow function.

ES6 How to get _this inside class, inside another context [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
I was searching and can't find a proper way to figure out this in ES6 way.
class MyClass {
// i can't event decalre _this/_self here
constructor() {
setTimeout(function(){
// other work..
hiUser(); // this.hiUser() or //_this.hiUser() not working
},1000);
}
hiUser(){
alert('Hi');
}
}
The previous answers only gave you code samples on how to fix it; Let me explain your issue and why it's happening
In your code example, the function inside of your setTimeout is being bound to the this value of the setTimeout (which is generally window or undefined in strict mode).
setTimeout(function () {
// this === window
}, 1000);
In ES6, they introduced lambda expressions (arrow functions) which are "lexically bound" -- meaning that they borrow the this value from their outside scope. In your case, that's the class/object.
In order to leverage the lambda expressions, it would look like:
class Foo {
constructor () {
setTimeout(() => this.myMethod(), 1000);
}
myMethod () {
console.log('foo');
}
}
If you're using Babel to transpile your code, and are using experimental features, you can use ES7's binding syntax to solve your problem as well.
If you bind a function/method, it creates a copy of that function, and binds the this value to whatever you choose. This will allow you to use the function statement that will be bound to your class/object.
<context to be bound> :: <function to receive context>
class Foo {
constructor () {
setTimeout(this::function() {
this.myMethod();
}, 1000);
}
myMethod () {
console.log('foo');
}
}
An even shorter version would look something like the following
constructor () {
setTimeout(this::this.myMethod, 1000);
}
If you're still having issues understanding this, I suggest you read more about ES6 classes and javascript binding.
You can use fat arrow functions:
class MyClass {
constructor() {
setTimeout(() => {
this.hiUser();
}, 1000);
}
hiUser(){
alert('Hi');
}
}
Or you can use the simple ES5's Function.prototype.bind method:
class MyClass {
constructor() {
setTimeout(function() {
this.hiUser();
}.bind(this), 1000);
}
hiUser(){
alert('Hi');
}
}
There is an ES7 proposal to shorthand the Function.prototype.bind method, so, depending on the transpiler (e.g Babel or Typescript) you're (possibly) using, you can set the ES7 flags and use it today:
class MyClass {
constructor() {
setTimeout(::function() {
this.hiUser();
}, 1000);
}
hiUser(){
alert('Hi');
}
}
setTimeout might have its own this context. You could set _self in the constructor though, or use arrow functions:
class MyClass {
constructor () {
var self = this;
// etc.
}
}

Categories

Resources