(编辑:jimmy 日期: 2024/11/18 浏览:2)
数据初始化
Vue 实例在建立的时候会运行一系列的初始化操作,而在这些初始化操作里面,和数据绑定关联最大的是 initState。
首先,来看一下他的代码:
function initState(vm) { vm._watchers = []; var opts = vm.$options; if(opts.props) { initProps(vm, opts.props); //初始化props } if(opts.methods) { initMethods(vm, opts.methods); //初始化methods } if(opts.data) { initData(vm); //初始化data } else { observe(vm._data = {}, true /* asRootData */ ); } if(opts.computed) { initComputed(vm, opts.computed); //初始化computed } if(opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch); //初始化watch } }
在这么多的数据的初始化中,props、methods和data是比较简单的(所以我就不详细介绍了"htmlcode">
function initComputed(vm, computed) { var watchers = vm._computedWatchers = Object.create(null); for(var key in computed) { var userDef = computed[key]; var getter = typeof userDef === 'function' "htmlcode">function initWatch(vm, watch) { //遍历watch,为每一个属性创建侦听器 for(var key in watch) { var handler = watch[key]; //如果属性值是一个数组,则遍历数组,为属性创建多个侦听器 //createWatcher函数中封装了vm.$watch,会在vm.$watch中创建侦听器 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) { //如果属性值是一个对象,则取对象的handler属性作为回调 if(isPlainObject(handler)) { options = handler; handler = handler.handler; } //如果属性值是一个字符串,则从组件实例上寻找 if(typeof handler === 'string') { handler = vm[handler]; } //为属性创建侦听器 return vm.$watch(expOrFn, handler, options) }computed
computed本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值
下面将围绕这一句话来做解释。
上面代码中提到过,当计算属性中的数据存在与data和props中时,会被警告,也就是这种做法是错误的。所以一般的,我们都会直接在计算属性中声明数据。还是那个代码片段中,如果定义的计算属性不在组件实例上,会运行defineComputed函数对数据进行数据劫持。下面我们来看下defineComputed函数中做了什么。
function defineComputed(target, key, userDef) { //是不是服务端渲染 var shouldCache = !isServerRendering(); //如果我们把计算属性的值写成一个函数,这时函数默认为计算属性的get if(typeof userDef === 'function') { sharedPropertyDefinition.get = shouldCache "_blank" href="https://www.jb51.net/article/159330.htm">vue响应式系统--observe、watcher、dep 中,我有关于Watcher的介绍中提到,计算属性 watcher实例化的时候,会把options.lazy设置为true,这里是计算属性惰性求值,且可缓存的关键,当然前提是cache不为false。cache不为false,会调用createComputedGetter函数创建计算属性的getter函数computedGetter,
先来看一段代码
function createComputedGetter(key) { return function computedGetter() { var watcher = this._computedWatchers && this._computedWatchers[key]; if(watcher) { if(watcher.dirty) { //watcher.evaluate中更新watcher的值,并把watcher.dirty设置为false //这样等下次依赖更新的时候才会把watcher.dirty设置为true,然后进行取值的时候才会再次运行这个函数 watcher.evaluate(); } //依赖追踪 if(Dep.target) { watcher.depend(); } //返回watcher的值 return watcher.value } } } //对于计算属性,当取值计算属性时,发现计算属性的watcher的dirty是true //说明数据不是最新的了,需要重新计算,这里就是重新计算计算属性的值。 Watcher.prototype.evaluate = function evaluate() { this.value = this.get(); this.dirty = false; }; //当一个依赖改变的时候,通知它update Watcher.prototype.update = function update() { //三种watcher,只有计算属性 watcher的lazy设置了true,表示启用惰性求值 if(this.lazy) { this.dirty = true; } else if(this.sync) { //标记为同步计算的直接运行run,三大类型暂无,所以基本会走下面的queueWatcher this.run(); } else { //将watcher推入观察者队列中,下一个tick时调用。 //也就是数据变化不是立即就去更新的,而是异步批量去更新的 queueWatcher(this); } };当options.lazy设置为true之后(仅计算属性watcher的options.lazy设置为true),每次依赖更新,都不会主动触发run函数,而是把watcher.dirty设置为true。这样,当对计算属性进行取值时,就会运行computedGetter函数,computedGetter函数中有一个关于watcher.dirty的判断,当watcher.dirty为true时会运行watcher.evaluate进行值的更新,并把watcher.dirty设置为false,这样就完成了惰性求值的过程。后面只要依赖不更新,就不会运行update,就不会把watcher.dirty为true,那么再次取值的时候就不会运行watcher.evaluate进行值的更新,从而达到了缓存的效果。
综上,我们了解到cache不为false的时候,计算属性都是惰性求值且具有缓存性的,而cache默认是true,我们也大多使用这个默认值,所以我们说 computed本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值 。
总结
以上所述是小编给大家介绍的vue数据初始化initState的实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
如果你觉得本文对你有帮助,欢迎转载,请注明出处,谢谢!