一、组件中的data为什么必须是一个函数?
一个组件被复用多次的话,就会创建多个实例。本质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于引用类型,会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数
二、Computed和watch
Computed本质是一个具备缓存的订阅者watcher,依赖的属性发生变化就会更新视图。适用于计算比较消耗性能的计算场景。当表达式过于复杂时,在模板中放入过多逻辑会让模板难以维护,可以将复杂的逻辑放入计算属性中处理。
Watch没有缓存性,更多的是观察的作用,可以监听某些数据执行回调。当我们需要深度监听对象中的属性时,可以打开deep:true选项,这样便会对对象中的每一项进行监听。这样会带来性能问题,优化的话可以使用字符串形式监听,如果没有写到组件中,不要忘记使用unWatch手动注销哦。
三、nextick实现原理是什么?
在下次 DOM 更新循环结束之后执行延迟回调。nextTick主要使用了宏任务和微任务。根据执行环境分别尝试采用 Promise (微任务) MutationObserver(微任务) setImmediate(宏任务) 如果以上都不行则采用setTimeout(宏任务) 定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过这个异步方法清空当前队列。 // 优先级 // 微任务process.nextTick>Promise>MutationObserve // 宏任务:整体代码script>setTimeout>setInterval>setImmediatesetImmediate(function () { console.log(1); }, 0); setTimeout(function () { console.log(2); }, 0); newPromise(function (resolve) { console.log(3); resolve(); console.log(4); }).then(function () { console.log(5); }); console.log(6); process.nextTick(function () { console.log(7); }); console.log(8); //输出结果是3 4 6 8 7 5 2 1
四、v-model的原理
v-model本质就是一个语法糖,可以看成是value + input方法的语法糖。
//可以通过model属性的prop和event属性来进行自定义。
原生的v-model,会根据标签的不同生成不同的事件和属性。
如下代码<input v-model="test">本质上是<input :value="test" @input="test = $event.target.value"> 在自定义组件中 <my-component v-model="inputValue"></my-component> 相当于 <my-component :value="inputValue" @input="inputValue = argument[0]"></my-component> 这个时候,inputValue接受的值就是input事件的回调函数的第一个参数,所以在自定义组件中,要实现数据绑定,还需要$emit去触发input的事件。 this.$emit('input', value)
五、Vue事件绑定原理说一下
原生事件绑定是通过addEventListener绑定给真实元素的,组件事件绑定是通过Vue自定义的$on实现的。
六.Vue模版编译原理
简单说,Vue的编译过程就是将template转化为render函数的过程。会经历以下阶段:
生成AST树
优化
codegen
首先解析模版,生成AST语法树(AST:抽象语法树,一种用JavaScript对象的形式来描述整个模板)。
使用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相关处理。
Vue的数据是响应式的,但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变化,对应的DOM也不会变化。那么优化过程就是深度遍历AST树,按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对它们的比对,对运行时的模板起到很大的优化作用。
编译的最后一步是将优化后的AST树转换为可执行的代码。