Vue defineReactive
John DoeVue defineReactive
核心原理
1 2 3 4 5 6 7 8 9 10 11 12
| function defineReactive(target, key, value) { Object.defineProperty(target, key, { get() { console.log('getter key = ', key) return value }, set(newV) { console.log(`setter ${key} = ${value}`) if (newV === value) return value = newV return value } }) }
|
对于数组和对象有不同的处理方式, 外面套一层
1 2 3 4 5 6 7 8 9 10 11
| function Observer(value) { if (Array.isArray(value)) { this.walk(value) } } Observer.prototype.walk = function (obj) { for (let key in obj) { defineReactive(obj, key, obj[key]) } }
|
为什么要用构造函数, vue源码是这么写的,😜
如果对象的值不是基本类型, 就无法设置响应式, 所以需要再加一层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| function defineReactive(target, key, value) { Object.defineProperty(target, key, { get() { console.log('getter key = ', key) return value }, set(newV) { console.log(`setter ${key} = ${value}`) if (newV === value) return value = newV return value } }) } function Observer(value) { if (Array.isArray(value)) { this.walk(value) } } Observer.prototype.walk = function (obj) { for (let key in obj) { defineReactive(obj, key, obj[key]) } } function observe(value) { if (typeof value !== 'object') return new Observer(value) }
|
基本类型变对象的处理
如果一个key原来的value是基本类型,新设置的value是对象,
也需要进行响应式出里
1 2 3 4 5 6 7 8 9 10 11 12 13
| function defineReactive(target, key, value) { Object.defineProperty(target, key, { get() { console.log('getter key = ', key) return value }, set(newV) { console.log(`setter ${key} = ${value}`) if (newV === value) return value = newV observe(value) } }) }
|
新增一个键值对
1 2 3
| function set(target, key, value) { defineReactive(target, key, value) }
|
对于数组的响应式处理
1 2 3 4 5 6 7 8 9 10 11
| const arrayProto = Array.prototypeconst arrayMethods = Object.create(arrayProto)
'push', 'pop', 'unshift', 'shift', 'splice', 'sort', 'reverse']
Object.defineProperty(arrayMethods, method, { value: function (...args) { const ret = arrayProto[method].apply(this, args) console.log('array reactive') return ret }, configurable: true, writable: true, enumerable: false, }) })
|
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| function defineReactive(target, key, value) { Object.defineProperty(target, key, { get() { console.log('getter key = ', key) return value }, set(newV) { console.log(`setter ${key} = ${value}`) if (newV === value) return value = newV observe(value) return value } }) } function Observer(value) { if (Array.isArray(value)) { value.__proto__ = arrayMethods } else { this.walk(value) } } Observer.prototype.walk = function (obj) { for (let key in obj) { defineReactive(obj, key, obj[key]) } } function observe(value) { if (typeof value !== 'object') return new Observer(value) } function set(target, key, value) { defineReactive(target, key, value) } const arrayProto = Array.prototypeconst arrayMethods = Object.create(arrayProto)
'push', 'pop', 'unshift', 'shift', 'splice', 'sort', 'reverse'] methodsToPatch.forEach(method => { Object.defineProperty(arrayMethods, method, { value: function (...args) { const ret = arrayProto[method].apply(this, args) console.log('array reactive') return ret }, configurable: true, writable: true, enumerable: false, }) }) const obj = { t: 't value', t1: { tt1: 'tt1 value' }, arr: [1, 2, 3] } observe(obj) obj.tobj.t1.tt1obj.t = { ttt: 'tttt value' } set(obj, 't2', 't2 value') obj.arr.push(5)
|
下面是输出
1 2 3 4 5 6 7
| getter key = t getter key = t1 getter key = tt1 setter t = t value getter key = t2 getter key = arr array reactive
|