vue2源码面试题

246 阅读3分钟

1.请说一下响应式数据的理解

  • 首先,在Vue初始化阶段,通过 observer 对 data 中的属性进行递归的劫持(若是对象的话采用Object.defineProperty重写get、set进行属性劫持,多层对象采用递归继续劫持;若是数组采用切片编程的思想对数组的方法进行重写)
  • 在Observe构造函数中有以下四部操作

    • 创建Dep
    • __ob__这个属性来判断对象是否被观测过
    • 判断属性是对象还是数组采用不同的方法进行属性劫持
  • 在我们属性重新定义时,存储Dep(每个属性都有一个Dep)

    • get()方法进行依赖收集,需要让dep存储watcher,若是多层时存储watcher(添加订阅者)
    • set()方法进行依赖更新,若用户的值改为对象时继续监控并赋值,且通知watcher队列进行操作(发布操作)(watcher.updata()去更新视图)

版本比较: vue是基于依赖收集的双向绑定; 3.0版本之前使用Object.definePropetry,3.0新版使用Proxy

  • 1.基于数据劫持/依赖收集 的双向绑定的优点 不需要显示的调用,Vue利用数据劫持+发布订阅,可以直接通知变化并且驱动视图 直接得到精确的变化数据,劫持了属性setter,当属性值改变,我们可以精确的获取变化的内容newValue,不需要额外的diff操作
  • 2.Object.defineProperty的缺点 不能监听数组:因为数组没有getter和setter,因为数组长度不确定,如果太长性能负担太大 只能监听属性,而不是整个对象,需要遍历循环属性 只能监听属性变化,不能监听属性的删减
  • 3.proxy的好处 可以监听数组 监听整个对象不是属性 13种来截方法,强大很多 返回新对象而不是直接修改原对象,更符合immutable;
  • 4.proxy的缺点 兼容性不好,而且无法用polyfill磨平;

2.Vue中模板编译原理

  • 第一步是将 模板字符串 转换成 element ASTs(解析器)
    • 解析器(parser)的原理是一小段一小段的去截取字符串,然后维护一个 stack 用来保存DOM深度,每截取到一段标签的开始就 push 到 stack 中,当所有字符串都截取完之后也就解析出了一个完整的 AST。
  • 第二步是对 AST 进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)
    • 优化器(optimizer)的原理是用递归的方式将所有节点打标记,表示是否是一个 静态节点,然后再次递归一遍把 静态根节点 也标记出来。
  • 第三步是 使用 element ASTs 生成 render 函数代码字符串(代码生成器)
    • 代码生成器(code generator)的原理也是通过递归去拼一个函数执行代码的字符串,递归的过程根据不同的节点类型调用不同的生成方法,如果发现是一颗元素节点就拼一个 _c(tagName, data, children) 的函数调用字符串,然后 data 和 children 也是使用 AST 中的属性去拼字符串。最后将字符串变成函数 限制取值范围 通过with来进行取值 稍后调用render函数就可以通过改变this 让这个函数内部取到结果了(模板引擎的实现原理就是new Function + with来进行实现的)