数据响应式原理
定义响应式对象 defineReactive
- Object.getOwnPropertyDescriptor 获取需要响应式观察对象对应键的自有属性描述符信息
- 判断自有属性是否存在并且是可以配置的
- 判断自有属性不存在get或者set存在,要修改的值为空对象或者undefined是将val重置为原始值
- 重新自定义get和set
function defineReactiveobj, key, val, customSetter, shallow = false, mock = false{ const dep = new Dep; const property = Object.getOwnPropertyDescriptorobj, key if property && property.configurable === false { return } const getter = property && property.get const setter = property && property.set if !getter setter && val === NO_INITIAL_VALUE arguments.length === 2 { val = obj[key] } let childOb = shallow ? val && val.__ob__ : observeval, false, mock Object.definePropertyobj, key, { enumerable: true, configurable: true, get: function reactiveGetter { const value = getter ? getter.callobj : val if Dep.target { dep.depend if childOb { childOb.dep.depend if isArrayvalue { dependArrayvalue } } } return isRefvalue && !shallow ? value.value : value }, set: function reactiveSetternewVal { const value = getter ? getter.callobj : val if !hasChangedvalue, newVal { return } if customSetter { customSetter } if setter { setter.callobj, newVal } else if getter { return } else if !shallow && isRefvalue && !isRefnewVal { value.value = newVal return } else { val = newVal } childOb = shallow ? newVal && newVal.__ob__ : observenewVal, false, mock dep.notify } } return dep}
深层对象递归观察 observe
function observevalue, shallow = false, ssrMockReactivity = false{ if value && hasOwnvalue, '__ob__' && value.__ob__ instanceof Observer { return value.__ob__ } return new Observervalue, shallow, ssrMockReactivity}class Observer{ constructorvalue, shallow, ssrMockReactivity{ this.dep = new Dep; this.vmCount = 0; defvalue, "__ob__", true ifisArrayvalue{ ifshallow{ this.observeArrayvalue } } else { const keys = Object.keysvalue for let i = 0; i < keys.length; i++ { const key = keys[i] defineReactivevalue, key, {}, undefined, shallow } } } observeArrayvalue{ for let i = 0, l = value.length; i < l; i++ { observevalue[i], false, false } }}
依赖收集 Dep
pendingCleanupDeps = [];class Dep { static target; constructor{ this.id = uid++; this.sub = []; this._pending = false } addSubsub{ this.sub.pushsub } removeSub{ this.subs[this.subs.indexOfsub] = null; if !this._pending { this._pending = true pendingCleanupDeps.pushthis } }, depend{ ifDep.target{ Dep.target.addDepthis } }, notify{ const subs = this.subs.filters => s for let i = 0, l = subs.length; i < l; i++ { subs[i].update } }}