拓展:数据的双向绑定原理
主要是通过observe函数对所有数据遍历,同时加上set,get方法,这样就能通过Object.defineProperty()劫持set、get。通过解析器对数据解析, 初始化之后会渲染页面,同时添加Watcher订阅者监听数据的变化.一旦数据变化就会立即收到通知,并且更新视图—(ps:Watch里面会在实例化的Dep中通过notice通知,从而调用update()触发数据更新)
不监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应
一、因为数组的位置不固定,数量多变,正常对象key对应value一般不会变,但是如果数组删除了某个元素,比如第一个元素被删除或者头部增加一个元素,那么将导致后面所有的key对应value错位,如果6个元素,也就会触发5次set。
二、数组元素可能非常非常多,每个元素进行劫持有一定浪费,这可能是Evan you对性能的考虑。
三、Vue将数组的7个变异方法进行了重写,也就是更改了Array原型上的方法达到劫持变化。
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
| const arr = [1, 2, 3, 4, 5, 6] for (let key in arr) { let value = arr[key] Object.defineProperty(arr, key, { get() { console.log(`get: ${key}`) return value }, set(newValue) { console.log(`set: ${key} to ${newValue}`) return value = newValue } }) }
arr[0] = 1 arr[3] arr.shift()
|
Proxy虽然是劫持的整个对象,但也是浅层劫持,属性值是对象时同样也需要深度遍历,不然该属性对象的变化也无法监测到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const obj = { count: 5, user: { name: 'JavaScript', age: 22 } }
const proxyObj = new Proxy(obj, { get(target, key) { console.log(`get:${key}`) return target[key] }, set(target, key, value) { console.log(`set:${key} to ${value}`) return target[key] = value } })
proxyObj.user.name = 'JenkinWoo'
|
当递归进行深度拦截
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 deepProxy(obj) { return new Proxy(obj, { get(target, key) { console.log(`get:${key}`) if (typeof target[key] === 'object' && target[key] !== null) { return deepProxy(target[key]) } return target[key] }, set(target, key, value) { console.log(`set:${key} to ${value}`) return target[key] = value } }) } const obj = { count: 5, user: { name: 'JenkinWoo', age: 22 } } const proxyObj = deepProxy(obj) proxyObj.user.name = 'JenkinWoo'
|
所以为什么proxy优于Object.defineProperty?
从以上的例子就能看到,Object.defineProperty必须“预先”劫持属性。被劫持的属性才会被监听到。所以后添加的属性,需要手动再次劫持。
而proxy代理了整个对象,不需要预先劫持属性,而是在获取/修改的时候,通过get/set方法来告诉你key。所以不管如何新增属性,总是能被捕获到。
作者:
JenkinWoo
日期:
05/23, 2023 11:11:00
分类:
Vue
归档:
https://www.65.gs/2023/05/04ab5075bd04.html