关于vue.js:我发现了华点vue规定用普通函数定义方法为什么react又要我用箭头函数

3次阅读

共计 3533 个字符,预计需要花费 9 分钟才能阅读完成。

原文首发在我的公众号,订阅可第一工夫查看我的最新文章!

大家好,我是年年!

如果应用过 react 和 vue,应该发现过一个问题:vue 通知咱们不应该把办法、生命周期用箭头函数去定义;而在 react 的类组件中,把办法写成箭头函数的模式却更不便。

要问其起因,大部分人都只把他当一个天经地义的规定。但把这个问题剖开,其实能很好地把筹备面试时造的火箭,在拧螺丝的时候用起来。

这篇文章能够让你在这个理论场景中去用到 this 的指向、作用域链以及原型。

this 指向失落

无论是 vue 还是 react,都在官网文档中强调,须要留神 this 的指向失落。但乏味的是,为了达到同样的目标,一个是不能应用箭头函数,一个是应用箭头函数便能解决

👇react

👇vue

React 中 this 的失落

首先来看看 react,这是一个很一般的类组件写法:

class Demo extends React.Component{
    state = {someState:'state'}
    // ✅举荐
    arrowFunMethod = () => {console.log('THIS in arrow function:',this)
        this.setState({someState:'arrow state'})
    }
    // ❌须要解决 this 绑定
    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'))

我在组件内我定义了两个办法:一个用箭头函数实现,另一个用一般函数。在调用时别离打印this,后果如下:

箭头函数中 this 正确指向了组件实例,但一般函数中却指向了 undefined,为什么?

其实这是一个无关 react 的 js 个性,剥离 react 带来的心智累赘,实质上,下面的代码不过是一个「类」,简化一下,就变成了这样👇:

 class ReactDemo {
    // ✅举荐
    arrowFunMethod = () => {console.log('THIS in arrow function:', this)
    }
    // ❌this 指向失落
    ordinaryFunMethod() {console.log('THIS in oridinary function:', this)
    }
  }
  const reactIns = new ReactDemo()
  let arrowFunWithoutCaller = reactIns.arrowFunMethod
  let ordinaryFunWithoutCaller = reactIns.ordinaryFunMethod
  arrowFunWithoutCaller()
  ordinaryFunWithoutCaller()

运行一下下面这段代码,会发现后果不出意料:在一般函数中 this 的指向也失落了。

从 react 代码运行的角度来解释一下:

首先是事件触发时,回调函数的执行。回调函数不是像这样间接由实例调用:reactIns.ordinaryFunMethod(),而是像下面代码中的,做了一次“代理”,最初被调用时,找不到调用对象了:ordinaryFunWithoutCaller()。这时就呈现了 this 指向 undefined 的状况。

但为什么应用箭头函数,this 又能够正确指向组件实例呢?首先回顾一个简略的知识点:class 是个语法糖,实质不过是个构造函数,把下面的代码用它最原始的样子写进去:

'use strict'
function ReactDemo() {
  // ✅举荐
  this.arrowFunMethod = () => {console.log('THIS in arrow function:', this)
  }
}
// ❌this 指向失落
ReactDemo.prototype.ordinaryFunMethod = function ordinaryFunMethod() {console.log('THIS in oridinary function:', this)
}
const reactIns = new ReactDemo()

能够看到:写成一般函数的办法,是被挂载到原型链上的;而应用箭头函数定义的办法,间接赋给了实例,变成了实例的一个属性,并且最重要的是:它是在「构造函数的作用域」被定义的。

咱们晓得,箭头函数没有本人的 this,用到的时候只能依据作用域链去寻找最近的那个。放在这里,也就是构造函数这个作用域中的this——组件实例。

这样就能够解释为什么 react 组件中,箭头函数的 this 能正确指向组件实例。

vue 中 this 的失落

把下面的组件用 vue 来写一遍:

const Demo = Vue.createApp({data() {
      return {someState:'state',}
  },
  methods:{
      // ❌this 指向失落
      arrowFunMethod:()=>{console.log('THIS in arrow function:',this)
          this.someState = 'arrow state'
      },
      // ✅举荐
      ordinaryFunMethod(){console.log('THIS in oridinary function:',this)
          this.someState = 'ordinary state'
      }
  },
  template:`
  <div>
      <h2>{{this.someState}}</h2>
      <button @click='this.arrowFunMethod'>call arrow function</button>
      <button @click='this.ordinaryFunMethod'>call ordinary function</button>
  </div>`
})
Demo.mount('#root')

运行代码,会发现后果对调了:应用箭头函数反而导致了 this 指向失落:this 指向了 window 对象

这部分解释起来会略微简单一下,不过也只波及一小块 vue 源码。次要的操作是 vue 对组件办法的解决,最外围的就三行,感兴趣的能够去看看残缺代码:vue-github

function initMethods(vm: Component, methods: Object) {for (const key in methods) {vm[key] = bind(methods[key], vm)
  }
}

vue 会把咱们传入 methods 遍历,再一个个赋给到组建实例上,在这个过程就解决了 this 的绑定(bind(methods[key], vm)):把每一个办法中的 this 都绑定到组件实例上。

一般函数都有本人的 this,所以绑定完后,被调用时都能正确指向组件实例。但箭头函数没有本人的 this,便无从谈及批改,它只能去找父级作用域中的 this。这个父级作用域是谁呢?是组件实例吗?咱们晓得作用域只有两种:全局作用域和函数作用域。回到咱们写的 vue 代码,它实质就是一个对象(具体一点,是一个组件的配置对象,这个对象外面有 data、mounted、methods 等属性)也就是说,咱们在一个对象外面去定义方法,因为对象不形成作用域,所以这些办法的父作用域都是全局作用域。箭头函数要去寻找 this,就只能找到全局作用域中的 this——window 对象了。

下面说了这么多,总结一下:vue 对传入的办法 methods 对象做了解决,在函数被调用前做了 this 指向的绑定,只有领有 this 的一般函数能力被正确的绑定到组件实例上。而箭头函数则会导致 this 的指向失落。

结语

「为什么 react 中用箭头函数,vue 中用一般函数」这是一个挺很有意思的问题,简略来说,这种差别是因为咱们写的 react 是一个类,而 vue 是一个对象导致的。

在类中定义只有箭头函数能力依据作用域链找到组件实例;在对象中,只有领有本身 this 的一般函数能力被批改 this 指向,被 vue 解决后绑定到组件实例。

如果感觉这篇文章对你有帮忙,不要忘了给我点个赞,你的反对是我最大的能源💗💗💗

关注我的公众号能够第一工夫看到最新文章👇👇👇

点个在看更好

正文完
 0