赞
踩
/src/core/observer/index.js
将一个正常的object转换为每个层级的属性都是响应式(可以被侦测的)的object;
// Observe.js import defineReactive from './defineReactive.js import arrayMethods from './rewriteArray.js' class Observer{ constructor(value){ def(value,'__ob__',this,flase). //给value对象绑定ob属性,且不可枚举 if(Array.isArray(value)){. //数组对象的处理 value.__proto__ = arrayMethods; //修改数组的隐式原型对象为更改后的数组原型对象 }else{ const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { const key = keys[i]; defineReactive(value, key); } } } observeArray(value) { for (let i = 0, l = value.length; i < l; i++) { observe(value[i], false); } } } var obj={ a:{ m:{ n:5 } }, b:[1,2,3] }
observe方法是最外层级的,上来先看observe(obj). —>>> obj身上有没有 __obj__ —>>> new Observer() ---->>> 遍历下一层属性,逐个defineReactive
/src/core/observer/index.js
//defineReactive.js文件 import observe from './observe.js export default function defineReactive(data,key,val){ if(arguments.length===2){ val=data[key] } //递归调用子元素,至此形成了递归,这个递归不是函数自己调用自己,而是多个函数,类循环调用; let childOb = observe(val) //返回val的ob对象 Object.defineProperty(data,key,{ //可枚举 enumrable:true, //可被配置,比如可以被删除delete configurable:true, //getter get(){ console.log('你试图访问obj的'+key+ '属性') return val }, set(newValue){ console.log('你试图改变obj的'+key+'属性‘,newValue) if(val===newValue){ return } val=newValue //当设置了新值,这个新值也要被observer childOb=observe(newValue) } } }
//index.js
import defineReactive from './defineReactive'
// 创建observe函数,注意函数的名字没有r,value其实是obj[key]
function observe(value){
if(typeof value != 'object') return;
//定义ob
var ob;
if(typeof value.__ob__ !== 'undefined'){
ob = value.__ob__;
}else {
ob = new Observer(value)
}
return ob
}
在这里插入图片描述
1.obj对象会先通过observe处理,看obj身上有没有__ob__属性;
2.没有则在Observe构造器中给obj对象添加__ob__属性; (精:def (obj,__ob__属性,this),这里的this指向的是实例化出来的observe对象,然后赋值给__ob__属性)
3.添加__ob__属性需要调用一个def方法:原因:__ob__属性不可枚举,所以单独使用一个def方法;
4.在Obsever类的构造器中遍历obj每一个属性,调用definReactive方法,进行数据劫持;
5.在遍历中如果该obj[key]是一个object对象,
src/core/observer/array.js
// rewriteArray.js //得到Array const arrayProto = Array.prototype; const arrayMethods = Object.create(arrayProto); //将数组的原型对象绑定在一个对象的原型上 //对数组的7个方法进行改造 const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ]; //重写方法 methodsToPatch.forEach(function (method) { // cache original method const original = arrayProto[method]; // mutator是给数组方法重新定义的一个方法 def(obj,key,value) def(arrayMethods, method, function mutator(...args) { const result = original.apply(this, args); //this是当前调用数组方法的对象,args是传进来的参数 const ob = this.__ob__; let inserted; // 给数组对象添加的元素 switch (method) { case 'push': case 'unshift': inserted = args; break; case 'splice': inserted = args.slice(2); break; } if (inserted) //给添加的所有元素绑定响应式 ob.observeArray(inserted); return result; }); }); export arrayMethods
/src/core/util/lang.js
export function def(obj: Object,key: string, val: any, enumerable?: boolean){
Object.definepProperty(obj,key,{
value: val,
enumerable: !!enumberable,
writable: true,
configurable: true,
}
}
/src/core/observer/index.js
/**
*设置 target._proto_的原型对象为src
*比如数组对象,arr.__proto__arrayMethods
*/
function protoAugment(target,src: Object){
target.__proto__ = src
}
/src/core/observer/index.js
/**
*在目标对象上定义指定属性
*比如数组:为数组对象定义那七个方法
*/
function copyAugment(target: Object, src:Object, keys: Array<string>){
for(let i=0; i=keys.length; i<l; i++){
const key = keys[i]
def(target, key, src[key])
}
}
/src/core/observer/dep.js
import type Watcher from './watcher' import {remove} from '../util/index' import {config} from '../config' let uid=0 /** *一个dep对应一个obj.key *在读取响应式数据时,负责收集依赖,每个dep(或者说obj.key)依赖的watcher有哪些 *在响应式数据更新时,负责通知dep中哪些watcher去执行update方法 */ export default class Dep { static target: ?Watcher; id: number; subs: Array<Watcher> } construcotr(){ this.id=uid++ this.subs=[] } //在dep中添加watcher addSub(sub: Watcher){ this.subs.push(sub) } removeSub(sub:Watcher){ remove(this.subs,sub} } //向watcher中添加dep depend(){ if(Dep.target){ Dep.target.addDep(this) } } /** *通知dep中所有watcher,执行watcher.update()方法 */ notify(){ const subs = this.subs.slice() if(process.env.NODE_ENV !== 'production' && !config.async){ subs.sort((a,b)=> a.id - b.id); } for(let i=0, l=subs.length;i<l;i++){ subs[i].update() } } /** *当前正在执行的watcher,同一时间只会有一个watcher执行 *Dep.target = 当前正在执行的watcher *通过调用pushTarget方法完成赋值,调用popTarget方法完成重置(null) */ Dep.target = null const targetStack = [] //在需要进行依赖收集的时候调用,设置Dep.target=watcher export function pushTarget (target: ?Watcher){ targetStack.push(target) Dep.target = target } //依赖收集结束调用,设置Dep.target = null export function popTarget(){ targetStack.pop() Dep.target = targetStack[targetStack.length-1] }
/src/core/observer/watcher.js
/** * 一个组件一个watcher(渲染watcher)或者一个表达式watcher(用户watcher) * 当数据更新时watcher会被触发,访问this.computedProperty时也会触发watcher */ export function class Watcher { vm: Component; expression: string; cb: Function; id: number; deep: boolean; user: boolean; lazy: boolean; sync: boolean; dirty: boolean; acive: boolean; deps: Array<Dep>; newDeps: Array<Dep>; depIds: SimpleSet; newDepIds: SimpleSet; before: ?Function; getter: Function; value: any; constructor( vm: Component, exOrFn: string | Function, cb: Function, options? : ?Object, isRenderWatcher? : boolean ){ this.vm = vm if(isRenderWatcher){ vm._watcher = this } vm._watchers.push(this) if(options){ this.deep = !!options.deep this.user = !!options.user this.lazy = !!options.lazy this.sync = !!options.sync this.before = options.before }else{ this.deep = this.user = this.lazy = this.sync =false } this.cb = cb this.id = ++uid this.active = true this.dirty = this.lazy this.deps = [] this.newDeps = [] this.depIds = new Set() this.newDepIds = new Set() this.expression = process.env.NODE_ENV !== 'production' ? expOrFn,toString() : '' if(typeof expOrFn === 'function'){ this.getter = expOrfn }else { // this.getter = function(){ return this.xx} //在this.get中执行this.getter 时会触发依赖收集 //待后续this.xx 更新时就会触发响应式 this.getter = parsePath(exOrfn) if(!this.getter){ this.getter = noop process.env.NODE_ENV !== 'production' && warn$2("Failed watching path: \"".concat(expOrFn, "\" ") + 'Watcher only accepts simple dot-delimited paths. ' + 'For full control, use a function instead.', vm); } } this.value = this.lazy ? undefined : this.get() } /** * 执行this.getter,并重新收集依赖 * this.getter 是实例化watcher时传递的第二个参数,一个函数或者字符串,比如updateComponent或者parsePath返回的读取this.xx属性值的函数 * 为什么要重新收集依赖? * 因为触发更新说明有响应式数据被更新了,但是被更新的数据虽然已经经过observe观察了,但是却没有进行依赖收集, * 所以,在更新页面时,会重新执行一次render函数,执行期间会触发读取操作,这时候进行依赖收集 */ get() { //打开Dep.target, Dep.target = this pushTarget(this) //value为回掉函数执行的结果 let value const vm = this.vm try{ //执行回掉函数,比如updateComponent ,进入patch阶段 value = this.getter.call(vm,vm) }catch(e){ if(this.user){ handleError(e,vm,`getter for watcher "${this.expression}"`} }else { throw e } }finally{ if(this.deep){ traverse(value) } //关闭Dep.target, Dep.target=null popTarget() this.cleanupDeps() } return value } /** * Add a dependency to this directive * 1.添加dep给自己(watcher) * 2.添加自己(watcher)到dep */ addDep(dep: Dep){ //判重,如果dep已经存在则不重复添加 const id = dep.id if(!this.newDepIds.has(id){ //缓存dep.id,用于判重 this.newDepIds.add(id) //添加 this.newDeps.push(dep) // 避免在dep中重复添加watcher,this.depIds 的设置在cleanDeps 方法中 if(!this.depIds.has(id){ //添加watcher自己到dep dep.addSub(this) } } } /** * Clean up for dependency collection */ cleanupDeps (){ let i = this.deps.length; while(i--){ const dep = this.deps[i] if(!this.newDepsIds.has(dep.id)){ dep.removeSub(this) } } let tmp = this.depIds this.depIds = this.newDepIds this.newDepIds = tmp this.newDepIds.clear() tmp = this.deps this.deps = this.newDeps this.newDeps = tmp this.newDeps.length = {} } /** *根据watcher配置项,决定接下来怎么走,一般是queueWatcher */ update(){ if(this.lazy){ //懒执行走这里,比如computed //将dirty 置为true,可以让computedGetter执行重新计算computed回掉函数的执行结果 this.dirty = true }else if(this.sync){ //同步执行,在使用vm.$watch或者watch选项时可以传一个sync选项 //当为true时在数据更新时该watcher就不走异步更新队列,直接执行this.run //方法进行更新 //这个属性在官方文档中没有出现 this.run() }else{ //更新时一般走这里,将watcher放入wacher队列 queueWatcher(this) } } /** * 由刷新队列函数flushSchedulerQueue调用,完成以下几件事: * 1.执行实例化watcher传递的第二个参数,updateComponent或者获取this.xx的的一个函数(parsePath 返回的函数) * 2.更新旧值为新值 * 3.执行实例化watcher时传递的第三个参数,比如用户watcher的回掉函数 */ run(){ if(this.active){ //调用this.get方法 const value = this.get() if( value !== this.value || isObject(value) || this.deep ){ // 更新旧值为新值 const oldValue = this.value this.value = value if(this.user){ //如果是用户watcher,则执行用户传递的第三个参数 ---回掉函数,参数为val和oldVal try{ this.cb.call(this.vm,value,oldValue) }catch(e){ handleError(e,this.vm,`callback for watcher "${this.expression}") } }else{ //渲染watcher,this.cb=noop,一个空函数 this.cb.call(this.vm,value,oldValue) } } } } /** * 懒执行watcher 会调用该方法 * 比如:computed,在获取vm.computedProperty 的值时会调用该方法 * 然后执行this.get,即watcher的回调函数,得到返回值 * this.dirty被置为fales,作用是页面在本次渲染只会一次执行computed.key的回掉函数, * 这也就是大家常说的computed和methods区别之一就是computed有缓存的原理所在 * 而页面更新后会this.dirty会重新置为true,这一步是在this.update方法中完成的 */ evaluate(){ this.value = this.get() this.dirty = false } /** * Depend on all deps collected by this watcher */ depend(){ let i = this.deps.length; while(i--){ this.deps[i].depend() } } /** * Remove self form all dependencies subscriber list */ teardown(){ if(this.active){ // remove self from vm's watcher list // this is a somewhat expensive operation so we skip it // if the vm is being destroyed if(!this.vm._isBeingDestoryed){ remove(this.vm._watcher,this) } let i = this.deps.length while(i--){ this.deps[i].removeSub(this) } this.active = false } } }
使用场景:
区别:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。