# fed-e-task-03-02 **Repository Path**: ternence07/fed-e-task-03-02 ## Basic Information - **Project Name**: fed-e-task-03-02 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-03-28 - **Last Updated**: 2021-03-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 简答题 ## 1、请简述 VUE 首次渲染的过程。 1. 初始化:初始化 vue 的实例成员、静态成员; 2. 初始化结束之后,调用 vue 构造函数。构造函数中调用了 this._init() ,这个方法相当于vue的入口,最终调用 vm.$mount() ; 3. 调用入口文件的 vm.$mount():这个方法主要是将模板编译成 render 函数。先判断是否传递了 render 选项,如果没有传递 render ,就把模板编译成 render 函数。这个过程是通过 compileToFunctions() 生成 render() 渲染函数 (new Function)。最后将 options.render = render; 4. 调用runtime版本中的vm.$mount():在这个方法中会重新获取 el 5. 调用 lifecycle.js 中的 mountComponent(this, el):方法中先判断是否有render选项,如果没有但是传入了模板,并且当前是开发环境的话会发送警告;触发 beforeMount ;然后定义 updateComponent ,这个方法中会调用 vm._render() 渲染虚拟dom ,调用 vm._update() 将虚拟dom转换成真实dom;然后创建 Watcher 实例,创建过程中传入了 updateComponent 会在 Watcher 内部调用 ,再调用 get() 方法;然后触发 mounted ,最终返回 vm ; 6. watcher.get():创建完 Watcher 会调用一次 get ,get内部调用 updateComponent() ;调用 vm._render() 创建 VNode :调用实例化时用户传入的 render 或者编译 template 生成的 render ,返回 VNode ;调用 vm._update() : 内部调用了 `vm.__patch__(vm.$el, vnode)` 去挂载真实dom 并记录 vm.$el ## 2、请简述 Vue 响应式原理。 (1)Vue 中的 init 方法开始的,然后出发 `initState()` 初始化Vue state状态;在 `initState()` 中调用 `initData()`, data属性注册到Vue 实力上;调用`observe()` 把 data 对象转换成 响应式对象(响应式入口)。 (2)`observe(value)` . 位置是 `src/core/observer/index.js`。判断接收到的参数value:判断value 事发后是对象,如果不是 对象直接返回;判断 value 对象是否有 `__ob__`,也就是看之前是否做过了响应式的处理,如果有直接返回,如果没有,就创建 observer 对象,之后返回 observer 对象。在创建 observer 类时,在构造函数中,给 value 对象定义不可枚举的 `__ob__` 属性,并把当前的 observer 对象记录 到 **ob** 中。之后,数组的响应式处理(pop, push, sort 等),对象的响应式处理(walk 方法,遍历 每个属性,对每个属性调用 `defineReactive`)。 (3)`defineReactive`。为每一个属性 创建 dep 对象,手机依赖。如果当前属性是对象,也要 把他 转换成响应式,调用 observe。其次,定义 getter 和 setter。`getter` 就是收集依赖,并返回属性值。`setter` 就是保存新值,如果新值是对象,调用 observe,派发更新 (发送通知),调用 `dep.notify()`。 (4)依赖收集过程。在 watcher 对象的 get 方法 中调用 `pushTarget` 记录 `Dep.target` 属性。访问 data 中的 成员 的时候收集依赖,`defineReactive` 的 `getter` 中 收集依赖。把属性对应的 watcher 对象添加到 dep 的 subs 数组中。给 `childOb` 收集依赖,目的是子对象添加和删除成员时发送通知。 (5)`watcher`。`dep.notify()` 在调用 watcher 对象的 `update()` 方法,其中 调用 queueWatcher() 判断 watcher 是否被 处理 ,如果没有的话添加到 queue 队列中 ,并调用 `flushSchedulerQueue()`。`flushSchedulerQueue()` 会触发 `beforeUpdate` 钩子函数。调用 `watcher.run()`,过程是 `run()⇒ get()⇒ getter() ⇒ updateComponent`,渲染 watcher,这时候数据已经更新到视图 上 ,在页面可以看见数据。然后就是清理过程,清空上一次的依赖,触发 `actived` 钩子函数,触发 `updated` 钩子函数。 ## 3、请简述虚拟 DOM 中 Key 的作用和好处 - 主要作用在Vue的虚拟算法中,在新旧nodes对比时,来辨识VNodes。 - 使用key来跟踪节点,可以使节点最大限度的得到重用。 - 在diff算法时,减少操作,优化性能。 ## 4、请简述 Vue 中模板编译的过程 Vue中模版的编译是如下过程:模版--->ast(抽象树)-->render 函数->虚拟 dom->实际 dom。 vue中的模版通过 compiler 编译成ast(用于表示模版的 js 对象,也可以说ast就是一个用来表示源代码的js对象),然后将ast生成对应render函数(这里先不谈关于ast的转化细节),render函数然后生成虚拟节点 vnode(用来描述节点及其子节点的信息),vnode的集合组成Virtual Dom(vue组件建立起来的整个vnode树叫虚拟Dom树),最后生成真实Dom