vue面试题及其结合源码分析之请说一下 vue响应式数据的理解

Vue面试题结合源码

  1. 请说一下 vue响应式数据的理解
  2. Vue中如何检测数组变化?
  3. Vue中如何进行依赖收集?
  4. 如何理解Vue中的模板编译原理
  5. Vue生命周期钩子是如何实现的
  6. Vue的生命周期方法有哪些?一般在哪一步发送请求及其原因
  7. Vue.mixin的使用场景和原理
  8. Vue组件data为什么必须是个函数?
  9. nextTick在哪里使用?使用原理?
  10. computedwatch的区别
  11. Vue.set方法是如何实现的
  12. Vue为什么需要虚拟dom
  13. Vuediff算法原理
  14. 既然Vue通过数据劫持可以精准探测数据变化,为什么还需要虚拟dom进行diff检测差异
  15. 请说明Vue中key的作用和其原理,谈谈你对它的理解
  16. 谈谈对Vue组件化的理解
请说一下 vue响应式数据的理解

可以监控一个数据的修改和获取操作。针对对象格式会给每个对象的属性进行劫持。其使用了Object.difineProperty方法。

关于vue的响应式原理我是有书写过的。内部就是在递归的劫持引用类型的属性,在属性也是引用类型的情况下会再次拦截。

回答该问题:

  1. 需要先找到基本的问题在哪
  2. 源码层面回答
  3. 使用的时候可能会伴随什么问题(就是踩坑)

源码层面:

  1. 先走 InitData方法
  2. observe
  3. defineReactive方法(内部对所有属性进行了重写,肯定是有性能消耗的)
  4. 在3中递归的观测引用类型的数据,给对象增加getter和setter

我们在使用vue的时候,如果data数据层级过深,需要考虑优化。比如:

  1. 数据不是响应式的,没必要放到data中

  2. 属性取值的时候,尽量避免多次取值

    for(let i = 0; i < 100; i++){
    	this.count++
    }
    // 优化 只会取值一次
    let count = this.count
    for(let i = 0; i < 100; i++){
    	count++
    }
    
  3. 如果有些对象是放到data中的,但是不需要是响应式的,可以考虑采用Object.freeze()冻结对象。冻结的对象Vue是不会进行观测的(一般这种对象都是会在模板中使用的数据)

    image-20220419223102194

源码分析:

new Vue的时候,来到了核心方法 _init。在该方法的 initState 方法用来初始化所有的状态信息。

image-20220419225657891

初始化data

image-20220419230122916

来到initData,该方法就是拿到data数据,然后进行判断,最后观测数据。

function initData (vm: Component) {
  let data = vm.$options.data
  // 顺便把 data也放在 _data属性上
  data = vm._data = typeof data === 'function'
    ? getData(data, vm) // data.call(vm)
    : data || {}
    // 不是计划的对象 data不是对象 或者data函数返回值不是对象
  if (!isPlainObject(data)) {
    data = {}
    process.env.NODE_ENV !== 'production' && warn(
      'data functions should return an object:\n' +
      'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
      vm
    )
  }
  // proxy data on instance
  const keys = Object.keys(data)
  const props = vm.$options.props
  const methods = vm.$options.methods
  let i = keys.length
  while (i--) {
    const key = keys[i]
    if (process.env.NODE_ENV !== 'production') {
      if (methods && hasOwn(methods, key)) {
        warn(
          `Method "${key}" has already been defined as a data property.`,
          vm
        )
      }
    }
    // props中有该属性
    if (props && hasOwn(props, key)) {
      process.env.NODE_ENV !== 'production' && warn(
        `The data property "${key}" is already declared as a prop. ` +
        `Use prop default value instead.`,
        vm
      )
    } else if (!isReserved(key)) { // 属性不要以 _ 和 $ 开头
        // 代理 vm._data
      // 访问 vm.name 代理到 vm._data.name
      proxy(vm, `_data`, key)
    }
  }
  // observe data 观测数据 标记整数根数据 new Vue
  observe(data, true /* asRootData */)
}

image-20220419230737819

在observe方法中,就是创建Observer观测者

image-20220419231313427

在这里就给引用类型创建观察者对象,如果该对象被观测过,直接返回观察过的observer对象.

观测的对象可能是数组,也可能是对象。

image-20220419231506826

如果是一个对象(不是数组对象),就把对象的每个属性变成响应式的数据。那么此时就会来到定义响应式数据的核心方法:defineReactive

walk (obj: Object) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      // 把对象的的每个 key 都变成响应式的
      defineReactive(obj, keys[i])
    }
  }

image-20220419233003398

defineReactive方法,Vue是给我们导出了的,在Vue.utils下,有该工具函数。

虽然vue内部是基本是没有使用过shallow参数进行引用类型数据的浅层观测的,但是把方法暴露给我们用户了,我们使用的时候是可以浅层观测对象的。

image-20220419234554437

可以自己尝试debugger看起响应式的过程。

image-20220419233448785

image-20220419234044426

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尤雨东

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值