在实际开发中,使用computed和mothod每每都能起到做用——返回或处理一个咱们要的值,可是适用场景不一样;好比:当咱们要去时刻监控一个视图层对应的数据层的值的变化时,使用computed就比较合理了,由于computed可缓存的,只要数据层所依赖的值不改变,computed就不会改变,而只要变了 ,computed的值就会实时更新到视图层上,即computed是响应式的。而在这个例子中,若是使用watch也能够实现,可是那就是对视图层对应的数据层的值的依赖数据进行监听,发生变化时再调用相应的函数更改该值,那么watch和computed又有什么区别呢? 异同以下:html
watch监听的值接收两个参数——新值、旧值 ,能够设置在初始化时调用vue
例:node
watch:监听一个属性值的变化并执行相应的函数数组
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName:"Foo Bar" }, watch:{ firstName:function(val){ this.fullName = val+this.lastName }, lastName:function(val){ this.fullName = this.firstName+val } } })
computed:依赖其余属性所计算出来的值缓存
var vm = new Vue({ el:'#demo', data:{ firstName: 'Foo', lastName:'Bar' }, computed:{ fullName(){ return this.firstName+this.lastName; } } })
var vm = new Vue({ el:'#demo', data:{ firstName:'Foo', lastName:'Bar' }, computed:{ fullName:{ get(){ return this.firstName + '·' + this.lastName }, set(newVal){ var name = NewVal.split('·') this.firstName = name[0]; this.lastName = name[name.length-1] } } } }) //运行vm.fullName = 'Kobe Bryant'时,set方法会被调用,vm.firstName和vm.lastName的值会被更新
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { console.log('第一次没有执行') this.fullName = val + '·' + this.lastName } } })
若是想firstName在第一次被绑定的时候就执行:dom
watch: { firstName: { handler(val){ console.log('第一次执行了') this.fullName = val + '·' + this.lastName }, immediate:true//在watch中声明后当即执行handler } }
var vm = new Vue({ el:'#demo', data:{ item:{ a:'', b:'' } }, watch:{ item:{ handler(val){ console.log('item.a changed') }, immediate: true } } }) //运行vm.item.a = '123',发现控制台没有打印“item.a changed”
改变item.a的值发现控制台没有打印字符串,这是由于vue没法检测到对象属性的添加或者删除。因为vue会在初始化实例时给实例的属性执行getter/setter转化过程,因此属性必须在data对象上存在才能让Vue转换它,才能是响应式的异步
默认状况下watch只监听对对象的引用,如当this.item = {a: '123',b:'123'}
执行时handler就会执行,ide
watch: { obj: { handler(val) { console.log('item.a changed') }, immediate: true, deep: true } }
deep的做用是:在对象一层层往下遍历,每一层都加上侦听器函数
可是使用deep属性会给每一层都加上监听器,性能开销可能就会很是大了。这样咱们能够用字符串的形式来优化:post
watch: { 'item.a': { handler(val) { console.log('item.a changed') }, immediate: true // deep: true } }
直到遇到'item.a'属性,才会给该属性设置监听函数,提升性能。
/* @flow */ import { _Set as Set, isObject } from '../util/index' import type { SimpleSet } from '../util/index' import VNode from '../vdom/vnode' const seenObjects = new Set() /** * Recursively traverse an object to evoke all converted * getters, so that every nested property inside the object * is collected as a "deep" dependency. */ export function traverse (val: any) { _traverse(val, seenObjects) seenObjects.clear() } function _traverse (val: any, seen: SimpleSet) { let i, keys const isA = Array.isArray(val) if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) { return } if (val.__ob__) { const depId = val.__ob__.dep.id if (seen.has(depId)) { return } seen.add(depId) } if (isA) { i = val.length while (i--) _traverse(val[i], seen) } else { keys = Object.keys(val) i = keys.length while (i--) _traverse(val[keys[i]], seen) } }
若是this.deep == true,即存在deep,则触发每一个深层对象的依赖,追踪其变化。traverse方法递归每个对象或者数组,触发它们的getter,使得对象或数组的每个成员都被依赖收集,造成一个“深(deep)”依赖关系。这个函数实现还有一个小的优化,遍历过程当中会把子响应式对象经过它们的 dep.id 记录到 seenObjects,避免之后重复访问。
参考学习: