《深入浅出Vue.js》读书笔记2-Proxy的自我尝试

简介: 《深入浅出Vue.js》读书笔记2-Proxy的自我尝试

1.问题


vue2.x用Object.defineProperty来劫持data数据的getter和setter操作。用这种方式实现了数据的变化侦测响应的功能,不过,Object.defineProperty存在一些天然的缺陷,包括:


1.Object.defineProperty的getter和setter只能侦测一个数据是否被修改,无法跟踪属性的删除和新增,就导致了对象里新增和删除属性无法被侦测到,(用proxy可以解决,Proxy的handler中有十三种劫持方式,比如deleteProperty可以劫持删除的操作)


2.上文 Object变化侦测中的 Observer实现中:


for(let i =0 ;i<keys.length;i++){
   defineReactive(obj,keys[i],obj[keys[i]])
}


通过遍历为对象的每一个属性设置getter/setter方式有些。。。(感觉不对,但是缺少形容词)。


3.Object.defineProperty存在先天的缺陷,无法监听数组变化,vue2.x使用了 用自己的方法覆盖数组原型的方式实现,于是我们可以捕捉到 push,pop,slice等操作,但是依然存在问题,比如:  gplArray[0]=1,这样的操作,无法对数据变化捕获。


2.proxy


概述: Proxy用于修改某些操作的默认行为,等同于语言层面做出修改,所以属于一种”元编程“,即对编程语言进行编程。 使用方式,比如:


var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`getting ${key}!`);
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, value, receiver) {
    console.log(`setting ${key}!`);
    return Reflect.set(target, key, value, receiver);
  }
});
obj.gpl = 1
//  setting gpl!
++obj.gpl
//  getting gpl!
//  setting gpl!
//  2


这个函数defineReactive用来对Object.defineProperty封装,并定义了一个响应式的数据。封装好后,每当从data的key读取数据,get函数被触发,每当往data的key中设置数据时,set函数被触发。


3.用proxy尝试重新实现上面代码


综上所述,以及Object变化侦测中用Object.defineProperty实现的老代码,尝试对Object变化侦测用proxy的方式进行重写。


//Observer
export class Observer {
    constructor (value) {
      this.value = value
      if(!Array.isArray(value)){
        this.walk(value)
      }
    }
    walk(obj) {
      const keys = Object.keys(obj)
      for(let i =0 ;i<keys.length;i++){
        defineReactive(obj,keys[i],obj[keys[i]])
      }
    }
  }
  //Object.defineProperty 的封装
  function defineReactive(data,key,val) {
    if(typeof val === 'object'){
      new Observer(val)
    }
    let dep = new Dep();
    Object.defineProperty(data,key,{
      enumerable:true,
      configurable:true,
      get:function(){
        dep.depend()
        return val;
      },
      set:function(newVal){
        if(val === newVal){
          return;
        }
        val = newVal;
        dep.notify();
      }
    })
  }
 //Dep
 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;i<subs.length;i++){
      subs[i].update()
    }
  }
}
  function remove(arr,item) {
    if(arr.length){
      const index = arr.indexOf(item);
      if(index > -1){
        return arr.splice(index,1)
      }
    }
  }


改写:


由于proxy可以直接监听对象每一个属性,所以dep我改成了Map(【key:[wather,...]】,...)的形式


export default class Dep {
    constructor(){
        this.subs = new Map();
    }
    addSub(key,watcher){
        let watcherList = this.subs.get(key)||[];
        if(!watcherList.includes(watcher)){
            watcherList.push(watcher);
            this.subs.set(key,watcher);
        }
    }
    removeSub(key){
        this.subs.delete(key)
    }
    depend(key){
        if(window.target){
            this.addSub(key,window.target)
        }
    }
    notify(key){
        let watcherList = this.subs.get(key);
        for(let watcher of watcherList){
            watcher.update()
        }
    }
}
export class Observer {
    constructor (value) {
        this.value = this.defineReactive(value)
    }
    static defineReactive(data){
        let dep = new Dep();
        return new Proxy(data,{
            get(obj, key) {
                dep.depend(key)
                return Reflect.get(obj, key);
            },
            set(obj, key, newVal) {
                Reflect.set(obj, key, newVal);
                dep.notify(key)
            }
        })
    }
}
//山寨超低配Vue
class Vue {
    constructor({data}) {
        this.$data = Observer.defineReactive(data());
    }
}
let vm = new Vue({
    data: () => ( {
      xxx:'gpl'
    }),
  });```


相关文章
|
7月前
|
缓存 JavaScript 数据安全/隐私保护
js开发:请解释什么是ES6的Proxy,以及它的用途。
`ES6`的`Proxy`对象用于创建一个代理,能拦截并自定义目标对象的访问和操作,应用于数据绑定、访问控制、函数调用的拦截与修改以及异步操作处理。
77 3
|
7月前
|
JSON JavaScript 前端开发
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)(下)
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)
97 2
|
1月前
|
JavaScript 前端开发 开发者
Vue 3中的Proxy
【10月更文挑战第23天】Vue 3中的`Proxy`为响应式系统带来了更强大、更灵活的功能,解决了Vue 2中响应式系统的一些局限性,同时在性能方面也有一定的提升,为开发者提供了更好的开发体验和性能保障。
77 7
|
1月前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
62 1
|
1月前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
63 1
|
3月前
vue2的响应式原理学“废”了吗?继续观摩vue3响应式原理Proxy
该文章对比了Vue2与Vue3在响应式原理上的不同,重点介绍了Vue3如何利用Proxy替代Object.defineProperty来实现更高效的数据响应机制,并探讨了这种方式带来的优势与挑战。
vue2的响应式原理学“废”了吗?继续观摩vue3响应式原理Proxy
|
4月前
|
缓存 JavaScript 安全
浅谈 Vue 3 的 Proxy 代理为什么使用了 Reflect
浅谈 Vue 3 的 Proxy 代理为什么使用了 Reflect
|
4月前
|
JavaScript 前端开发 开发者
Vue.js 响应式变革来袭!结合热点技术,探索从 Object.defineProperty 到 Proxy 的奇妙之旅,触动你的心
【8月更文挑战第30天】在 Vue.js 中,响应式系统自动追踪并更新数据变化,极大提升了开发体验。早期通过 `Object.defineProperty` 实现,但存在对新旧属性处理及数组操作的局限。Vue 3.0 引入了 `Proxy`,克服了上述限制,提供了更强大的功能和更好的性能。实践中,可根据项目需求选择合适的技术方案,并优化数据操作,利用懒加载等方式提升性能。
48 0
|
5月前
|
API
vue3 原理【详解】Proxy 实现响应式
vue3 原理【详解】Proxy 实现响应式
54 0
|
5月前
|
设计模式 JavaScript 前端开发
精读JavaScript中的代理(Proxy)与反射(Reflect)
精读JavaScript中的代理(Proxy)与反射(Reflect)
51 0