vue源码解析data与watcher
以一份简单的例子说明:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src='node_modules/vue/dist/vue.js' type='text/javascript'></script> </head> <body> <div id='app'></div> <script type='text/javascript'> var vueIns=new Vue({ data(){ return { aaa:1, bbb:2 } }, created(){ this.aaa =3 }, methods:{ confirm(){ this.bbb=333 } }, template:'<div><h1>{{aaa}}</h1><h2>{{bbb}}</h2></div>' }).$mount('#app') console.log(vueIns) </script> </body> </html>
Vue对象中的data对象
Observer.prototype.walk = function walk (obj) { var keys = Object.keys(obj); for (var i = 0; i < keys.length; i++) { defineReactive$$1(obj, keys[i]); } }; /** * Define a reactive property on an Object. */ function defineReactive$$1 ( obj, key, val, customSetter, shallow ) { var dep = new Dep(); var property = Object.getOwnPropertyDescriptor(obj, key); if (property && property.configurable === false) { return } // cater for pre-defined getter/setters var getter = property && property.get; var setter = property && property.set; if ((!getter || setter) && arguments.length === 2) { val = obj[key]; } var childOb = !shallow && observe(val); Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { var value = getter ? getter.call(obj) : val; if (Dep.target) { dep.depend(); if (childOb) { childOb.dep.depend(); if (Array.isArray(value)) { dependArray(value); } } } return value }, set: function reactiveSetter (newVal) { var value = getter ? getter.call(obj) : val; /* eslint-disable no-self-compare */ if (newVal === value || (newVal !== newVal && value !== value)) { return } /* eslint-enable no-self-compare */ if (customSetter) { customSetter(); } // #7981: for accessor properties without setter if (getter && !setter) { return } if (setter) { setter.call(obj, newVal); } else { val = newVal; } childOb = !shallow && observe(newVal); dep.notify(); } }); }
将_data的数据进行遍历defineProperty
得到:vm.aaa的形式
_data: aaa: 3 bbb: 2 __ob__: Observer {value: {…}, dep: Dep, vmCount: 1} get aaa: ƒ reactiveGetter() set aaa: ƒ reactiveSetter(newVal) get bbb: ƒ reactiveGetter() set bbb: ƒ reactiveSetter(newVal)
代理:proxy方法
proxy(vm, "_data", key); function proxy (target, sourceKey, key) { sharedPropertyDefinition.get = function proxyGetter () { return this[sourceKey][key] }; sharedPropertyDefinition.set = function proxySetter (val) { this[sourceKey][key] = val; }; Object.defineProperty(target, key, sharedPropertyDefinition); }
得到
aaa: 3 bbb: 2 __proto__: Object get aaa: ƒ proxyGetter() set aaa: ƒ proxySetter(val) get bbb: ƒ proxyGetter() set bbb: ƒ proxySetter(val)
数据监控执行
initWatch
function initWatch (vm, watch) { for (var key in watch) { var handler = watch[key]; if (Array.isArray(handler)) { for (var i = 0; i < handler.length; i++) { createWatcher(vm, key, handler[i]); } } else { createWatcher(vm, key, handler); } } } function createWatcher ( vm, expOrFn, handler, options ) { if (isPlainObject(handler)) { options = handler; handler = handler.handler; } if (typeof handler === 'string') { handler = vm[handler]; } return vm.$watch(expOrFn, handler, options) } Vue.prototype.$watch = function ( expOrFn, cb, options ) { var vm = this; if (isPlainObject(cb)) { return createWatcher(vm, expOrFn, cb, options) } options = options || {}; options.user = true; var watcher = new Watcher(vm, expOrFn, cb, options); if (options.immediate) { try { cb.call(vm, watcher.value); } catch (error) { handleError(error, vm, ("callback for immediate watcher \"" + (watcher.expression) + "\"")); } } return function unwatchFn () { watcher.teardown(); } }; }