手写Vue2.0响应式原理

时间:2025-04-08 09:21:06
class Vue { constructor(options) { this.$options = options this.$data = options.data // 重写数组方法 let arrayPrototype = Array.prototype const methods = ['pop', 'push', 'shift', 'unshift'] this.proto = Object.create(arrayPrototype) methods.forEach(method => { this.proto[method] = function() { arrayPrototype[method].call(this, ...arguments) } }) // 响应化 this.observe(this.$data) // 测试代码 // new Watcher(this, 'test') // // 创建编译器 // new Compile(, this) if (options.created) { options.created.call(this) } } // 递归遍历,使传递进来的对象响应化 observe(value) { if (!value || typeof value !== 'object') { return } if (Array.isArray(value)) { Object.setPrototypeOf(value, this.proto) } Object.keys(value).forEach(key => { // 对key做响应式处理 this.defineReactive(value, key, value[key]) this.proxyData(key) }) } // 在Vue根上定义属性代理data中的数据,这样就能通过 this 调用数据 proxyData(key) { Object.defineProperty(this, key, { get() { return this.$data[key] }, set(newVal) { this.$data[key] = newVal } }) } defineReactive(obj, key, val) { // 递归响应,处理嵌套对象 this.observe(val) // 创建Dep实例: Dep和key一对一对应 const dep = new Dep() // 给obj定义属性 Object.defineProperty(obj, key, { get() { // 将指向的Watcher实例加入到Dep中, 这部分是收集依赖 Dep.target && dep.addDep(Dep.target) console.log('get') return val }, set(newVal) { if (newVal !== val) { val = newVal console.log('set') // (`${key}属性更新了`) dep.notify() // 通知视图更新 } } }) } } // Dep: 管理若干watcher实例,它和key一对一关系 class Dep { constructor() { this.deps = [] } addDep(watcher) { this.deps.push(watcher) } notify() { this.deps.forEach(watcher => watcher.update()) } } // 实现update函数可以更新 class Watcher { constructor(vm, key, cb) { this.vm = vm this.key = key this.cb = cb // 将当前实例指向 Dep.target = this this.vm[this.key] Dep.target = null } update() { console.log(`${this.key}属性更新了`) this.cb.call(this.vm, this.vm[this.key]) } }