You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
export functionset(target: Array<any>|Object,key: any,val: any): any{// 判断是否为数组且下标是否有效if(Array.isArray(target)&&isValidArrayIndex(key)){// 调用 splice 函数触发派发更新// 该函数已被重写target.length=Math.max(target.length,key)target.splice(key,1,val)returnval}// 判断 key 是否已经存在if(keyintarget&&!(keyinObject.prototype)){target[key]=valreturnval}constob=(target: any).__ob__if(target._isVue||(ob&&ob.vmCount)){process.env.NODE_ENV!=='production'&&warn('Avoid adding reactive properties to a Vue instance or its root $data '+'at runtime - declare it upfront in the data option.')returnval}// 如果对象不是响应式对象,就赋值返回if(!ob){target[key]=valreturnval}// 进行双向绑定defineReactive(ob.value,key,val)// 手动派发更新ob.dep.notify()returnval}
Vue 初始化
在 Vue 的初始化中,会先对 props 和 data 进行初始化
接下来看下如何初始化 props 和 data
Object.defineProperty
无论是对象还是数组,需要实现双向绑定的话最终都会执行这个函数,该函数可以监听到
set
和get
的事件。在
Object.defineProperty
中自定义get
和set
函数,并在get
中进行依赖收集,在set
中派发更新。接下来我们先看如何进行依赖收集。依赖收集
依赖收集是通过
Dep
来实现的,但是也与 Watcher 息息相关对于 Watcher 来说,分为两种 Watcher,分别为渲染 Watcher 和用户写的 Watcher。渲染 Watcher 是在初始化中实例化的。
接下来看一下 Watcher 的部分实现
以上就是依赖收集的全过程。核心流程是先对配置中的 props 和 data 中的每一个值调用
Obeject.defineProperty()
来拦截set
和get
函数,再在渲染 Watcher 中访问到模板中需要双向绑定的对象的值触发依赖收集。派发更新
改变对象的数据时,会触发派发更新,调用
Dep
的notify
函数以上就是派发更新的全过程。核心流程就是给对象赋值,触发
set
中的派发更新函数。将所有 Watcher 都放入nextTick
中进行更新,nextTick
回调中执行用户 Watch 的回调函数并且渲染组件。Object.defineProperty 的缺陷
以上已经分析完了 Vue 的响应式原理,接下来说一点
Object.defineProperty
中的缺陷。如果通过下标方式修改数组数据或者给对象新增属性并不会触发组件的重新渲染,因为
Object.defineProperty
不能拦截到这些操作,更精确的来说,对于数组而言,大部分操作都是拦截不到的,只是 Vue 内部通过重写函数的方式解决了这个问题。对于第一个问题,Vue 提供了一个 API 解决
对于数组而言,Vue 内部重写了以下函数实现派发更新
The text was updated successfully, but these errors were encountered: