智者不为愚者谋,勇者不为怯者死。这篇文章主要讲述《深入浅出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 = https://www.songbingjia.com/android/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)
改写:
【《深入浅出Vue.js》读书笔记2-Proxy的自我尝试】由于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 = https://www.songbingjia.com/android/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,推荐阅读
- 《深入浅出Vue.js》读书笔记1-Object的变化侦测
- 草系前端是如何筹备第一个b站视频的(!努力写个稿子吧)
- k8s—pod基础
- Tomcat Session管理分析面试+工作
- k8s—pod进阶(资源限制,健康检查)
- vi/vim基本使用方法
- Centos6.5安装配置mongodb
- IT人不要一辈子靠技术生存
- 集群(cluster)