Es6 Functions, Arrow Functions And 'this' In An Es6 Class
Solution 1:
It's important to know that this syntax:
classA {
method = () => {}
}
is just syntactic sugar for creating an instance method in the class constructor:
classA {
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):
classA {
constructor() {
this.method = () =>this;
}
}
const instance = newA();
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).
classA {
method() {}
}
console.log(newA().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:
classA {
constructor() {
this.methodOnInstance = () =>this;
}
methodOnPrototype() { returnthis; }
}
const instance = newA();
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)
classA {
constructor() {
this.methodOnInstance = () =>this;
}
methodOnPrototype() { returnthis; }
}
const instance = newA();
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):
classA {
constructor() {
this.methodOnInstance = this.methodOnPrototype.bind(this);
}
methodOnPrototype() { returnthis; }
}
const instance = newA();
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:
classA {
constructor() {
this.method = this.method.bind(console);
}
method() { returnthis; }
}
const instance = newA();
console.log(
instance.method() === console// true
);
Solution 2:
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}`;
}
Solution 3:
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.
Solution 4:
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.
Solution 5:
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 validthis.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})
Post a Comment for "Es6 Functions, Arrow Functions And 'this' In An Es6 Class"