function defineReactive(data, key, val) {
// let dep = []; //收集依赖
// if (typeof val === 'object') {
// new Observer(val)
// }
let childOb = observe(val) //修改
let dep = new Dep() //修改
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
// window.target 为全局唯一依赖
// dep.push(window.target)
dep.depend() //添加依赖
// 这里手机Array的依赖
if (childOb) {
childOb.dep.depend()
}
return val
},
set: function (newVal) {
if (val === newVal) {
return
}
// 循环触发依赖
// for (let i = 0; i < dep.length; i++) {
// dep[i](newVal, val)
// }
val = newVal;
dep.notify() // 调用dep类的notify,循环通知
}
})
}
// 封装Dep类 创建Dep用来收集依赖,删除依赖和向依赖发消息等操作 而所谓的依赖就是下面封装的Watcher类
export default class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
removeSub(sub) {
remove(this.subs, sub)
}
depend() {
if (window.target) {
this.addSub(window.target)
}
}
notify() {
const subs = this.subs.slice()
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
}
function remove(arr, item) {
if (arr.length) {
//查找缓存的依赖的下标
const index = arr.indexOf(item)
if (index > -1) {
//删除依赖
return arr.splice(index, 1)
}
}
}
// window.target 抽象
// eg:
// vm.$watch('a.b.c', function (newVal, oldVal) {
// //someThing
// })
/**
* 依赖
* 所谓依赖就是Watcher,只有Watcher触发的getter才会收集依赖,那个Watcher出发了getter,就把那个watcher收集到dep中,当数据发生变化时,会循环依赖列表,把所有的依赖(wathcer)都通知一遍
* 原理是把自己設置到全局唯一的制定位置,例如window.taeget,然后读取数据。因为读取了数据 所以触发这个数据的getter,接着就会在getter从全局唯一制定的位置读取当前正在读取数据的Watcher并收集到dep中。
* 通过这种方式可以主动去订阅任意一个数据的变化。
* */
export default class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm
// 执行this.getter(),就可以读取data.a.b.c的内容
this.getter = parsePath(expOrFn)
this.cb = cb
this.value = this.get()
}
get() {
window.target = this
let value = this.getter.call(this.vm, this.vm)
window.target = undefined
return value
}
update() {
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm, this.value, oldValue)
}
}
/**
* 解析简单路径
**/
const bailRE = /[^\w.$]/
function parsePath(path) {
if (bailRE.test(path)) {
return
}
const segments = path.split('.')
return function (obj) {
for (let i = 0; i < segments.length; i++) {
if (!obj) return
obj = obj[segments[i]]
}
return obj;
}
}
// 工具函数
function def(obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
})
}
// 递归侦测所有Key
/**
* Observer 类会附加到每一个被侦测的Object上
* 一旦被附加上,Observer会将object的所有属性转换为getter/setter的形式
* 未收集属性的依赖,并且当属性发生变化时会通知这些依赖
*
* 作用把一个object中所有的数据转换为响应式的。
* 侦测一个Object中所有的数据包括子数据的变化,
* 因为ES6之前没有元编程的能力,所以删除和新增属性都无法被侦测到,后续的Vue3会使用proxy重写
* */
// __proto__是否可用
const hasProto = '__proto__' in {}
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
export class Observer {
constructor(value) {
this.value = value
this.dep = new Dep(); //新增Dep
def(value, '__ob__', this) //新增
if (Array.isArray(value)) {
this.observeArray(value)
} else {
this.walk(value)
}
if (Array.isArray(value)) {
// value.__proto__ = arrayMethods // 新增
const augment = hasProto ? protoAugment : copyAugment
augment(value, arrayMethods, arrayKeys)
} else {
this.walk(value)
}
}
/**
* walk会将每一个属性都转换为getter/setter的形式来侦测变化
* 这个方法只有数据类型为Object时被调用
* */
walk(obj) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i], obj[keys[i]])
}
}
/**
* 侦测Array中的每一项
*/
observeArray(items) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}
function protoAugment(target, src, keys) {
target.__proto__ = src
}
function copyAugment(target, src, keys) {
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i]
def(target, key, src[key])
}
}
// 数组的变化侦听
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) {
//缓存原始方法
const original = arrayProto[method]
// Object.defineProperty(arrayMethods, method, {
// value: function mutator(...args) {
// const ob = this.__ob__ // 新增 获取Observer实例
// return original.apply(this, args)
// },
// enumerable: false,
// writable: true,
// configurable: true
// })
def(arrayMethods, method, function mutator(...args) {
const result = original.apply(this, args)
const ob = this.__ob__ // 新增 获取Observer实例
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break;
case 'splice':
inserted = args.slice(2)
break;
}
if (inserted) ob.observeArray(inserted)
ob.dep.notify() // 向依赖发送消息
return result
})
})
/**
* 尝试为value创建一个Observer实例,
* 如果创建成功,直接返回新创建的Observer实例。
* 如果value已经存在一个Observer实例,则直接返回它
* */
export function observe(value, asRootData) {
if (!isObject(value)) {
return
}
let ob
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__
} else {
ob = new Observer(value)
}
return ob
}
var hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn (obj, key) {
return hasOwnProperty.call(obj, key)
}
Comments | NOTHING