vue在初始化的时候,在initState方法中会调取initData方法初始化data数据,对data对象进行遍历,在这个方法中会调observe,让数据变得响应式。
-
在observe函数中会获取value上的__ob__属性指向的Observer实例,如果这个属性没有被定义,就会根据数据创建一个Observer实例
-
Observer类会给每个value打上__ob__属性,值为该Observer实例,表示这个value已经被转化成响应式的了。
接下来将会对数据类型进行判断:
-
对象则遍历**对象**的属性(利用walk()方法)调用`defineReactive` -
数组:`调用observeArray`(),遍历数组的元素,递归调用observe
- defineReactive 函数方法内部使用
Object.defineProperty对数据进行劫持,在getter中收集依赖,setter中通知依赖更新。
-
get中通过Dep类实例,dep.depend触发**Watcher(订阅者)** 的依赖收集,收集订阅者;如果是数组则遍历数组,将数组中的每个值都通过depend添加到依赖。 -
set时会对数据进行对比,如果数据没有发生变化就不会进行派发更新,变化了则通过 dep.notify()发布通知,通知所有依赖更新,遍历所有依赖,依次执行watcher的update方法
单独说数组---- 数组则通过重写数组方法来实现的【push,pop.shift,unshift.splice,sort.reverse】。 流程
- 以Array.prototype为原型创建一个对象arrayMethods对象
- 让响应式数组继承自arrayMethods
- 遍历数组方法
缺陷:无法对除了这7个方法之外的修改数组进行响应式--因此
Vue增加了两个全局API:Vue.set和Vue.delete
let arr = [1,2,3]
arr[0] = 5; // 通过数组下标修改数组中的数据
arr.length = 0 // 通过修改数组长度清空数组
不容易理解的
window.target和dep.target 就是一个watcher对象,我们在dep实例中收集watcher对象的目的就是在数据发生变化时,能够调用收集到的watcher对象的update方法来更新视图
重要函数
1.Observe 函数
获取value上的 __ob__属性指向的Obverser实例,如果该属性未定义,根据数据创建一个Obverser实例; 在实例化是会向value添加 __ob__属性
2.Observer类
-
是一个工厂函数,将一个正常的object转换为每一个层级的属性都是响应式的
3.defineReactive方法
-
给数据添加响应式,在getter中收集依赖,setter中通知依赖更新
4.Dep类
-
依赖收集管理器
5.watcher类
-
连接表达式和值,说白了就是 watcher 连接视图层的依赖,并可以触发视图层的更新,与 Dep 紧密结合,通过 Dep 来控制其对视图层的监听
6.cached 方法--生成带有缓存的函数
export function cached<F: Function> (fn: F): F {
const cache = Object.create(null)
return (function cachedFn (str: string) {
const hit = cache[str] // 如果已缓存,hit就是有数据的,如果未缓存hit 就是 undefined
return hit || (cache[str] = fn(str)) // hit 没有数据,那么就调用fn 将str缓存起来并返回
}: any)
7.camelize 将我们字符串的命名规则转换为 骆驼命名规则
const camelizeRE = /-(\w)/g
export const camelize = cached((str: string): string => {
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})
对象的响应式处理
(1)让object数据变的可观测
-
--利用object.defineProperty(),将该属性的读和写,利用get()和set()进行拦截
数组的响应式处理
以Array.prototype 为原型创建了一个arrayMethods对象,并强制让数组的 proto 指向arrayMethods