3、Vue的computed与watch的区别在哪里?
我们先看一个例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <p>{{a}}</p> <p>{{b}}</p> <p>{{c}}</p> <button @click='change'>change</button> </div> </body> <script src="vue.js"></script> <script> var vm =new Vue({ el:'#app', data:{ a:1, b:2 }, methods:{ change(){ this.a = 5; } }, watch:{ a(){ console.log('watch'); } }, computed:{ c(){ console.log('computed'); return this.a + this.b; } } }) </script> </html>
一开始的时候,
点击按钮时,
我们可以看到一开始的时候,打印出了computed
,当点击按钮时,data
内的属性值a
发生变化,打印出watch
,接着我们不停点击按钮,并没有打印。(?查看总结4)
我们来总结一下,
- 最本质的区别,
computed
为计算属性,watch
为监听属性。 watch
就是单纯的监听某个数据的变化,支持深度监听。computed
是计算属性,是依赖于某个或者某些属性值,当依赖值发生变化时,也会发生变化。- 计算属性不在
data
中,计算属性依赖值在data
中。watch
监听的数据在data
中。(不一定在只是data
,也可能是props
) watch
用于观察和监听页面上的vue实例,当你需要在数据变化响应时,执行异步操作,或高性能消耗的操作,那么watch
为最佳选择。computed
可以关联多个实时计算的对象,当这些对象中的其中一个改变时都会触发这个属性,具有缓存能力,所以只有当数据再次改变时才会重新渲染,否则就会直接拿取缓存中的数据。computed
是在Dep.update()
执行之后,数据更新之前,对数据重新改造。watch
是在set
刚开始发生的时候添加的回调,可以监听数据的变化。
4、为什么在Vue3.0采用了Proxy,抛弃了Object.defineProperty?
Object.defineProperty
无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。为了解决这个问题,经过Vue内部处理后可以使用以下几种方法来监听数组。
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
由于只针对以上八种方法进行了hack处理,所以其他数组的属性方法也是检测不到的,还是具有一定的局限性。
这里我们举个例子,可以看得更加明白:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <ul> <li v-for='item in watchArr'>{{item.name}}</li> </ul> <button @click='change'>change</button> </div> </body> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { watchArr: [{ name: '1', },{ name: '2', }], }, methods: { change() { this.watchArr =[{ name: '3', }]; this.watchArr.splice(0, 1); this.watchArr[0].name = 'xiaoyue'; // 无法监听 this.watchArr.length = 5; // 无法监听 } }, watch: { watchArr(newVal) { console.log('监听了'); }, } }) </script> </html>
想必看到上面的例子我们会更加明白Object.defineProperty
的局限性。接下来,我们接着说Object.defineProperty
只能劫持对象的属性,因此,我们需要对每个对象的每个属性进行遍历。Vue2.0里,是通过递归+遍历data对象来实现对数据的监控的,如果属性值也是对象的话,那么需要深度遍历。显然如果能够劫持一个完整的对象才是更好的选择。
那么Proxy有以下两个优点:
- 可以劫持整个对象,并返回一个新对象
- 有13种劫持操作
摒弃 Object.defineProperty
,基于Proxy
的观察者机制探索
5、为什么Vuex的mutation不能做异步操作?
因为更改state的函数必须是纯函数,纯函数既是统一输入就会统一输出,没有任何副作用;如果是异步则会引起额外的副作用,导致更改后的state不可预测。
6、Vue中的computed是如何实现的?
实质是一个惰性的wather
,在取值操作时根据自身标记dirty属性返回上一次计算结果或重新计算值在创建时就进行一次取值操作,收集依赖变动的对象或属性(将自身压入dep
中),在依赖的对象或属性变动时,仅将自身标记dirty
致为true
。
7、Vue的父组件和子组件的生命周期钩子函数执行顺序是什么?
- 加载渲染过程 (父)beforeCreate → (父)created → (父)beforeMount → (子)beforeCreate → (子)created → (子)beforeMount → (子)mounted → (父)mounted
- 子组件更新过程 (父)beforeUpdate → (子)beforeUpdate → (子)Updated → (父)Updated
- 父组件更新过程 (父)beforeUpdate → (父)Updated
- 销魂过程 (父)beforeDestroy → (子)beforeDestory → (子)destroyed → (父)destroyed