The original article was first published on my official account, subscribe to the first time to view my latest article!
Hello everyone, I am Nian nian!
If you’ve used React and Vue, you’ve noticed one problem: Vue tells you not to define methods and life cycles with arrow functions. In the React class component, it’s more convenient to write methods as arrow functions.
To ask why, most people take it as a matter of course. But cracking this question open can actually be a great way to use the rockets you build in preparation for an interview when it comes to turning the screws.
This article allows you to use the this pointer, scope chain, and prototype in the real world.
This is lost
Both Vue and React emphasize in the official documentation that it is necessary to pay attention to the lost direction of this. But the interesting thing is, in order to achieve the same goal, one is you can’t use the arrow function, and the other is you can use the arrow function
π react
π vue
Loss of this in React
Let’s start with react. This is a very common class component:
class Demo extends React.Component{
state = {
someState:'state'
}
/ / β
recommendations
arrowFunMethod = () = > {
console.log('THIS in arrow function:'.this)
this.setState({someState:'arrow state'})}// β needs to handle the this binding
ordinaryFunMethod(){
console.log('THIS oridinary function:'.this)
this.setState({someState:'ordinary state'})}render(){
return (
<div>
<h2>{this.state.someState}</h2>
<button onClick={this.arrowFunMethod}>call arrow function</button>
<button onClick={this.ordinaryFunMethod}>call ordinary function</button>
</div>
)
}
}
ReactDOM.render(<Demo/>.document.getElementById('root'))
Copy the code
I defined two methods within the component: one implemented with arrow functions and one with normal functions. Print this separately when called, resulting in the following result:
The arrow function refers to the component instance correctly, but the normal function refers to undefined. Why?
This is a javascript feature that doesn’t have anything to do with React. If you remove the mental burden of React, the above code is essentially just a “class”.
class ReactDemo {
/ / β
recommendations
arrowFunMethod = () = > {
console.log('THIS in arrow function:'.this)}// βthis is lost
ordinaryFunMethod() {
console.log('THIS in oridinary function:'.this)}}const reactIns = new ReactDemo()
let arrowFunWithoutCaller = reactIns.arrowFunMethod
let ordinaryFunWithoutCaller = reactIns.ordinaryFunMethod
arrowFunWithoutCaller()
ordinaryFunWithoutCaller()
Copy the code
If you run the code above, you’ll find the unexpected result: the reference to this is also missing in normal functions.
React code to explain how it works:
The first is the execution of the callback function when the event is triggered. The callback function is not directly by the instances like this call: reactIns. OrdinaryFunMethod (), but as in the code above, made a “proxy”, finally is called, can’t find the call object: ordinaryFunWithoutCaller (). This points to undefined.
But why does this point correctly to the component instance using the arrow function? Class is a syntactic sugar. It is essentially a constructor. Write the above code in its original form:
'use strict'
function ReactDemo() {
/ / β
recommendations
this.arrowFunMethod = () = > {
console.log('THIS in arrow function:'.this)}}// βthis is lost
ReactDemo.prototype.ordinaryFunMethod = function ordinaryFunMethod() {
console.log('THIS in oridinary function:'.this)}const reactIns = new ReactDemo()
Copy the code
As you can see, the method of writing ordinary functions is attached to the prototype chain; The method defined using the arrow function is assigned directly to the instance, becomes an attribute of the instance, and, most importantly, is defined “in the scope of the constructor.”
As we know, arrow functions do not have their own this, so they can only find the nearest one based on the scope chain. Put here, in the constructor’s scope, the this — component instance.
This explains why in the React component, the arrow function this points to the component instance correctly.
Loss of this in vue
Write the above components in vue:
const Demo = Vue.createApp({
data() {
return {
someState:'state',}},methods: {// βthis is lost
arrowFunMethod:() = >{
console.log('THIS in arrow function:'.this)
this.someState = 'arrow state'
},
/ / β
recommendations
ordinaryFunMethod(){
console.log('THIS in oridinary function:'.this)
this.someState = 'ordinary state'}},template:`
{{this.someState}}
`
})
Demo.mount('#root')
Copy the code
When I run the code, I find that the result is reversed: using the arrow function instead causes this to be lost: this refers to the window object
This part is a bit more complicated to explain, but only involves a small piece of vue source code. The main operation is vue’s handling of component methods, the core of the three lines, interested in the full code: VUe-Github
function initMethods(vm: Component, methods: Object) {
for (const key in methods) {
vm[key] = bind(methods[key], vm)
}
}
Copy the code
Vue iterates through our methods and assigns them to the component instance one by one, handling the bind of this (methods[key], VM) : bind this from each method to the component instance.
Normal functions have their own this, so they can be called with the correct reference to the component instance. But the arrow function doesn’t have its own this, so it can’t talk about modifying it. It has to find this in its parent scope. Who is the parent scope? Is it a component instance? We know that there are only two types of scope: global scope and functional scope. Back to our writing vue code, its essence is an object (specifically, is a component of a configuration object, this object contains data, mounted, the methods and attributes) that is to say, we are in an object to define method, because the object does not constitute a scope, so the parent scope of these methods are global scope. To find this, the arrow function can only find the this — window object in the global scope.
To sum up: Vue handles the methods object passed in and binds this before the function is called. Only ordinary functions that have this are bound to the component instance correctly. The arrow function causes the this pointer to be lost.
conclusion
React is a class, while vue is an object.
Define in a class that only arrow functions can find component instances by scope chain; In objects, only ordinary functions that have their own this can be modified to refer to this, processed by vUE, and bound to the component instance.
If you find this article helpful, don’t forget to give me a thumbs up. Your support is my biggest motivation πππ
Follow my official account for the first time to see the latest article πππ
Click to follow better πππ