vue面试题目|收集依赖,react和vue的区别

27. Vue是如何收集依赖的?

在初始化 Vue 的每个组件时,会对组件的 data 进行初始化,就会将由普通对象变成响应式对象,在这个过程中便会进行依赖收集的相关逻辑,如下所示∶

function defieneReactive (obj, key, val){
  const dep = new Dep();
  ...
  Object.defineProperty(obj, key, {
    ...
    get: function reactiveGetter () {
      if(Dep.target){
        dep.depend();
        ...
      }
      return val
    }
    ...
  })
}

以上只保留了关键代码,主要就是 const dep = new Dep()实例化一个 Dep 的实例,然后在 get 函数中通过 dep.depend() 进行依赖收集。(1)DepDep是整个依赖收集的核心,其关键代码如下:

class Dep {
  static target;
  subs;

  constructor () {
    ...
    this.subs = [];
  }
  addSub (sub) {
    this.subs.push(sub)
  }
  removeSub (sub) {
    remove(this.sub, sub)
  }
  depend () {
    if(Dep.target){
      Dep.target.addDep(this)
    }
  }
  notify () {
    const subs = this.subds.slice();
    for(let i = 0;i < subs.length; i++){
      subs[i].update()
    }
  }
}

Dep 是一个 class ,其中有一个关 键的静态属性 static,它指向了一个全局唯一 Watcher,保证了同一时间全局只有一个 watcher 被计算,另一个属性 subs 则是一个 Watcher 的数组,所以 Dep 实际上就是对 Watcher 的管理,再看看 Watcher 的相关代码∶(2)Watcher

class Watcher {
  getter;
  ...
  constructor (vm, expression){
    ...
    this.getter = expression;
    this.get();
  }
  get () {
    pushTarget(this);
    value = this.getter.call(vm, vm)
    ...
    return value
  }
  addDep (dep){
        ...
    dep.addSub(this)
  }
  ...
}
function pushTarget (_target) {
  Dep.target = _target
}

Watcher 是一个 class,它定义了一些方法,其中和依赖收集相关的主要有 get、addDep 等。(3)过程在实例化 Vue 时,依赖收集的相关过程如下∶初 始 化 状 态 initState , 这 中 间 便 会 通 过 defineReactive 将数据变成响应式对象,其中的 getter 部分便是用来依赖收集的。初始化最终会走 mount 过程,其中会实例化 Watcher ,进入 Watcher 中,便会执行 this.get() 方法,

updateComponent = () => {
  vm._update(vm._render())
}
new Watcher(vm, updateComponent)

get 方法中的 pushTarget 实际上就是把 Dep.target 赋值为当前的 watcher。

this.getter.call(vm,vm),这里的 getter 会执行 vm.render() 方法,在这个过程中便会触发数据对象的 getter。那么每个对象值的 getter 都持有一个 dep,在触发 getter 的时候会调用 dep.depend() 方法,也就会执行 Dep.target.addDep(this)。刚才 Dep.target 已经被赋值为 watcher,于是便会执行 addDep 方法,然后走到 dep.addSub() 方法,便将当前的 watcher 订阅到这个数据持有的 dep 的 subs 中,这个目的是为后续数据变化时候能通知到哪些 subs 做准备。所以在 vm.render() 过程中,会触发所有数据的 getter,这样便已经完成了一个依赖收集的过程。

28. 对 React 和 Vue 的理解,它们的异同

相似之处:

●都将注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库

;●都有自己的构建工具,能让你得到一个根据最佳实践设置的项目模板;

●都使用了Virtual DOM(虚拟DOM)提高重绘性能

;●都有props的概念,允许组件间的数据传递;

●都鼓励组件化应用,将应用分拆成一个个功能明确的模块,提高复用性。不同之处 :1)数据流Vue默认支持数据双向绑定,而React一直提倡单向数据流2)虚拟DOMVue2.x开始引入"Virtual DOM",消除了和React在这方面的差异,但是在具体的细节还是有各自的特点。

●Vue宣称可以更快地计算出Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。

●对于React而言,每当应用的状态被改变时,全部子组件都会重新渲染。当然,这可以通过 PureComponent/shouldComponentUpdate这个生命周期方法来进行控制,但Vue将此视为默认的优化。

3)组件化React与Vue最大的不同是模板的编写。

●Vue鼓励写近似常规HTML的模板。写起来很接近标准 HTML元素,只是多了一些属性。

●eact推荐你所有的模板通用JavaScript的语法扩展——JSX书写。具体来讲:React中render函数是支持闭包特性的,所以import的组件在render中可以直接调用。但是在Vue中,由于模板中使用的数据都必须挂在 this 上进行一次中转,所以 import 一个组件完了之后,还需要在 components 中再声明下。

4)监听数据变化的实现原理不同

●Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能●React 默认是通过比较引用的方式进行的,如果不优化(PureComponent/shouldComponentUpdate)可能导致大量不必要的vDOM的重新渲染。这是因为 Vue 使用的是可变数据,而React更强调数据的不可变。

5)高阶组件react可以通过高阶组件(HOC)来扩展,而Vue需要通过mixins来扩展。高阶组件就是高阶函数,而React的组件本身就是纯粹的函数,所以高阶函数对React来说易如反掌。相反Vue.js使用HTML模板创建视图组件,这时模板无法有效的编译,因此Vue不能采用HOC来实现。

6)构建工具两者都有自己的构建工具:

●React ==> Create React APP

●Vue ==> vue-cli7)跨平台

●React ==> React Native

●Vue ==> Weex

另外一个属性subs则是watcher的数组,所以dep实际上就是对watcher的管理

具体来说react当中的render函数是支持闭包特性的,所以import的组件在render当中可以直接调用,但是在vue当中,由于模板当中使用的数据都必须挂载this上进行依次中专,所以import一个组件完了以后,还需要再compoents当中再次声明一下

所以import的组件再render当中可以直接调用的,但是再vue当中,由于模板当中使用数据都必须挂载this上进行一次中专,所以import一个组件完了以后

vue通过getter/setter以及一些函数的劫持,能够精确直到数据的变化,不需要特别的优化九年能够达到很好的性能

react默认通过比较引用的方式进行的,如果不要头花pureComponent/shouldComponentUpdate可能会导致大量不必要的vDom的重新渲染,这是因为vue使用的是可变的数据,而react更强掉数据的不可变的、

vuejs使用html模板创建视图组件,这个时候模板无法有效编译的,因此vue不能采用hoc来实现的。

全部评论

相关推荐

点赞 5 评论
分享
牛客网
牛客企业服务