# part3-modul1 **Repository Path**: ren_wei_1/part3-modul1 ## Basic Information - **Project Name**: part3-modul1 - **Description**: No description available - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-08-29 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 一、简答题 ### 1、当我们点击按钮的时候动态给 data 增加的成员是否是响应式数据,如果不是的话,如何把新增成员设置成响应式数据,它的内部原理是什么。 ```javascript let vm = new Vue({ el: '#el' data: { o: 'object', dog: {} }, method: { clickHandler () { // 该 name 属性是否是响应式的 this.dog.name = 'Trump' } } }) ``` 通过这种方式增加的成员不是响应式数据,vue中是无法检测到property的添加或者移除的,所以通过这种方式添加的属性不是响应式的。通过源码,我们可以知道vue在把数据转换成响应式的代码是在observer中的,而observer只有在vue创建的时候会执行,里面的方法只有在创建vue或者执行setter的时候会将数据转换为响应式的。我们上面这种改变方式不会触发set,所以就不会把这个属性设置为响应式的 ```javascript defineReactive(data, key, value) { const that = this; this.walk(data[key]); // 负责收集依赖 并发送通知 let dep = new Dep(); Object.defineProperty(data, key, { enumerable: true, configurable: true, get() { // 收集依赖 Dep.target && dep.addSub(Dep.target); return value; }, set(newValue) { if (newValue === value) return; value = newValue; that.walk(newValue); dep.notify(); } }); } ``` 解决方法:在vue的官方文档中提供了api方法,通过Vue.set(vm.dog, 'name', 2),set里面的具体代码基本如下,具体的逻辑就是调用Vue的set方法,然后再通过defineReactive的函数来把这个数据设置成为响应式的 ```js function set (target, key, val) { if (isUndef(target) || isPrimitive(target) ) { warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target)))); } if (Array.isArray(target) && isValidArrayIndex(key)) { target.length = Math.max(target.length, key); target.splice(key, 1, val); return val } if (key in target && !(key in Object.prototype)) { target[key] = val; return val } var ob = (target).__ob__; if (target._isVue || (ob && ob.vmCount)) { warn( 'Avoid adding reactive properties to a Vue instance or its root $data ' + 'at runtime - declare it upfront in the data option.' ); return val } if (!ob) { target[key] = val; return val } defineReactive$$1(ob.value, key, val); ob.dep.notify(); return val } ``` ### 2、请简述 Diff 算法的执行过程 1. diff算法有三大策略(Tree Diff => Component Diff => Element Diff)执行是按照这个顺序执行的 2. 首先是Tree Diff ,Tree Diff是对树的每一层进行遍历,找出每一层中的不同 3. 然后再是component diff,如果两个组件相同的话,则继续比较component中的子节点即可 4. 如果两个组件不同的话,则会移除掉old Component中的所有子节点 5. 最后是element diff 这里面的逻辑是这样的,按照下面的顺序执行(依次判断) - 如果满足newStart和oldStart相同 > 调用patchVnode来对节点进行更新 > > newStart++; > > oldStart++; - 如果newEnd和oldEnd相同 > 调用patchVnode进行更新 > > oldEnd--; > > newEnd--; - 如果oldStart和newEnd相同 > 进行移动,oldStart移动到oldEnd后面 > > oldStart++; > > newEnd--; - 如果oldEnd和newStart相同 > 进行移动,把oldEnd移动到oldStart前面 > > oldEnd--; > > newStart++; - 如果都不满足的话 >首先获取newStart节点看在oldVnode中存不存在 > >存在的话就把那个节点移动到oldStart前面 > >如果不存在的话就在oldStart前面创建一个element > >newStart++; 整体流程如下图 ![输入图片说明](https://s1.ax1x.com/2020/08/30/dqIdhR.gif "在这里输入图片标题")