VUE逐点突破系列 -- VUE高精尖面试题解析

VUE逐点突破系列 – VUE高精尖面试题解析

newVue()都做了什么

  1. newVue()是创建Vue实例,它内部执行了根实例的初始化过程。
  2. 具体包括以下操作:
  • 选项合并用户选项、默认选项
  • $children, $refs, $slots, $createElement等实例属性和方法初始化
  • 自定义事件处理
  • 数据响应式处理
  • 生命周期钩子调用
  • 可能的挂载
  1. 总结:newVue()创建了根实例并准备好数据和方法,未来执行挂载时,此过程还会递归的应用于它的子组件上,终形成⼀个有紧密关系的组件实例树。

说⼀说你对vue响应式理解

  1. 所谓数据响应式就是用户对数据层做的更改能够触发视图层做出更新响应的机制。
  2. mvvm框架中要解决的⼀个核心问题是连接数据层和视图层,通过数据驱动应用,数据变化,视图更新,要做到这点的就需要实现⼀套响应式机制,这样⼀旦数据发生变化就可以立即做出更新处理。
  3. 以vue为例说明,通过数据响应式加上虚拟DOM和patch算法,可以使我们只需要操作数据,完全不用接触繁琐的dom操作,从而大大提升开发效率,降低开发难度。
  4. vue2中的数据响应式会根据数据类型来做不同处理,如果是对象则采用Object.defineProperty()的方式定义数据拦截,当数据被访问或发生变化时,我们感知并作出响应;如果是数组则通过覆盖该数组原型的方法,扩展它的7个变更方法,使这些方法可以额外的做更新通知,从而作出响应。这种机制很好的解决了数据响应化的问题,但在实际使用中也存在⼀些缺点:比如初始化时的递归遍历会造成性能损失;新增或删除属性时需要用户使用Vue.set/delete这样特殊的api才能生效;对于es6中新产生的Map、Set这些数据结构不⽀持等问题。
  5. 为了解决这些问题,vue3重新编写了这⼀部分的实现:利用ES6的Proxy机制代理要响应化的数据,它有很多好处,编程体验是⼀致的,不需要使用特殊api,初始化性能和内存消耗都得到了大幅改善;另外由于响应化的实现代码抽取为独立的reactivity包,使得我们可以更灵活的使用它,我们甚至不需要引⼊vue都可以体验。

你知道nextTick吗

  1. nextTick是Vue提供的⼀个全局API,由于vue的异步更新策略导致我们对数据的修改不会立刻体现在dom变化上,此时如果想要立即获取更新后的dom状态,就需要使用这个方法
  2. Vue在更新DOM时是异步执行的。只要侦听到数据变化,Vue将开启⼀个队列,并缓冲在同⼀事件循环中发生的所有数据变更。如果同⼀个watcher被多次触发,只会被推⼊到队列中⼀次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作是⾮常重要的。nextTick方法会在队列中加⼊⼀个回调函数,确保该函数在前面的dom操作完成后才调用。
  3. 所以当我们想在修改数据后立即看到dom执行结果就需要用到nextTick方法。
  4. 比如,我在干什么的时候就会使用nextTick,传⼀个回调函数进去,在里面执行dom操作即可。
  5. 我也有简单了解nextTick实现,它会在callbacks里面加⼊我们传⼊的函数,然后用timerFunc异步方式调用它们,首选的异步方式会是Promise。这让我明白了为什么可以在nextTick中看到dom操作结果。

你知道key的作用吗

  1. key的作用主要是为了更高效的对比虚拟DOM中的某个节点是否是相同节点。
  2. vue在patch过程中判断两个节点是否是相同节点是key是⼀个必要条件,渲染⼀组列表时,key往往是唯⼀标识,所以如果不定义key的话,vue只能认为比较的两个节点是同⼀个,哪怕它们实际上不是,这导致了频繁更新元素,使得整个patch过程比较低效,影响性能。
  3. 实际使用中在渲染⼀组列表时key必须设置,而且必须是唯⼀标识,应该避免使用数组索引作为key,这可能导致⼀些隐蔽的bug;vue中在使用相同标签元素过渡切换时,也会使用key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
  4. 从源码中可以知道,vue判断两个节点是否相同时主要判断两者的key和元素类型等,因此如果不设置key,它的值就是undefined,则可能永远认为这是两个相同节点,只能去做更新操作,这造成了大量的dom更新操作,明显是不可取的。

简单谈谈你对VUEX的了解

  1. vuex是vue专用的状态管理库。它以全局方式集中管理应用的状态,并且可以保证状态变更的可预测性。
  2. vuex主要解决的问题是多组件之间状态共享的问题,利用各种组件通信方式,我们虽然能够做到状态共享,但是往往需要在多个组件之间保持状态的一致性,这种模式很容易出现问题,也会使程序逻辑变得复杂。vuex通过把组件的共享状态抽取出来,以全局单例模式管理,这样任何组件都能用一致的方式获取和修改状态,响应式的数据也能够保证简洁的单向数据流动,我们的代码将变得更结构化且易维护。
  3. vuex并非必须的,它帮我们管理共享状态,但却带来更多的概念和框架。如果我们不打算开发大型单页应用或者我们的应用并没有大量全局的状态需要维护,完全没有使用vuex的必要。一个简单的store 模式就足够了。反之,Vuex 将会成为自然而然的选择。引用 Redux 的作者 Dan Abramov 的话说就是:Flux 架构就像眼镜:您自会知道什么时候需要它。
  4. 我在使用vuex过程中有如下理解:首先是对核心概念的理解和运用,将全局状态放入state对象中,它本身一棵状态树,组件中使用store实例的state访问这些状态;然后有配套的mutation方法修改这些状态,并且只能用mutation修改状态,在组件中调用commit方法提交mutation;如果应用中有异步操作或者复杂逻辑组合,我们需要编写action,执行结束如果有状态修改仍然需要提交mutation,组件中调用这些action使用dispatch方法派发。最后是模块化,通过modules选项组织拆分出去的各个子模块,在访问状态时注意添加子模块的名称,如果子模块有设置namespace,那么在提交mutation和派发action时还需要额外的命名空间前缀。
  5. vuex在实现单项数据流时需要做到数据的响应式,通过源码的学习发现是借用了vue的数据响应化特性实现的,它会利用Vue将state作为data对其进行响应化处理,从而使得这些状态发生变化时,能够导致组件重新渲染。

Vue2和Vue3中的响应式原理对比,分别的具体实现思路

  1. vue2数据响应式实现根据对象类型做不同处理,如果是object,则通过Object.defineProperty(obj,key,descriptor)拦截对象属性访问
function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get() {
      return val
    },
    set(v) {
      val = v
      notify()
    }
  })
}

如果是数组,则覆盖数组的7个变更方法实现变更通知

const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)

;['push','pop','shift','unshift','splice','sort','reverse']
  .forEach(function (method) {
  const original = arrayProto[method]
  def(arrayMethods, method, function mutator (...args) {
    const result = original.apply(this, args)
    notify()
    return result
  })
})
  1. 可以看到vue2中有几个问题:

初始化时需要遍历对象所有key,如果对象层级较深,性能不好
通知更新过程需要维护大量dep实例和watcher实例,额外占用内存较多。

动态新增、删除对象属性无法拦截,只能用特定set/delete api代替
不支持新的Map、Set等数据结构。

  1. vue3中为了解决以上问题,使用原生的Proxy代替:
function defineReactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      track(target, key)
      return Reflect.get(target, key)
    },
    set(target, key, val) {
      Reflect.set(target, key, val)
      trigger(target, key)
    },
    deleteProperty(target, key) {
      Reflect.deleteProperty(target, key)
      trigger(target, key)
    }
  })
}

可以同时支持object和array,动态属性增、删都可以拦截,新增数据结构均支持,对象嵌套属性运行时递归,用到才代理,也不需要维护特别多的依赖关系,性能取得很大进步。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值