监听对象的操作
const obj = {
name: 'xi',
age:20
}
Object.keys(obj).forEach(key=>{
let value = obj[key]
Object.defineProperty(obj,key,{
get:function(){
console.log(`${key}属性被访问`)
return value
}
set:function(newValue){
console.log(`${key}属性被设置值`)
value = newValue
}
})
})
无法监听更多的操作,比如删除,新增
Proxy 代理 函数
const obj = {
name:'xi',
age:20
}
//设置obj的代理对象,第一个参数为目标对象,第二个参数为重写捕获器Trap,如果不重写则传入一个空对象
const objProxy = new Proxy(obj,{
//三个参数,第一个目标对象,二参数目标属性,三参数代理对象
get:function (target,key){
console.log('对象属性被访问')
return target[key]
}
set:function(target,key,newValue){
console.log('对象属性被设置值')
target[key] = newValue
}
})
Proxy有13种操作捕获器
const obj = {
name:'xi',
age:20
}
const objProxy = new Proxy(obj,{
//监听in操作
has:function(target,key){
return key in target
}
//监听delete操作
deleteProperty:function(target,key){
delete target[key]
}
})
Reflect 反射 对象
const obj = {
name:'xi',
age:20
}
const objProxy = new Proxy(obj,{
get:function(target,key){
Reflect.get(target,key)
}
set:function(target,key,newValue){
Reflect.set(target,key,newValue)
//操作成功与否会返回一个布尔值,可以根据布尔值来进行其他操作
}
})
Receiver
const obj = {
_name:'xi',
get name(){
return this._name
}
set name(newValue){
this._name = newValue
}
}
const objProxy = new Proxy(obj,{
get:function(target,key,recevier){
return Reflect.get(target,key,recevier)
}
set:function(target,key,newValue,recevier){
return Reflect.set(target,key,newValue,recevier)
//传入recevier时会改写obj中的this一次,此时Reflect执行时访问的是objProxy对象
//首先访问objProxy,之后在访问obj对象本身,共访问两次
}
})
响应式
当对象中的参数值进行修改时,可以自动再次执行某段代码
class Depend {
constructor(){
this.reactiveFns = []
}
addDepend(reactiveFn){
this.reactiveFns.push(reactiveFn)
}
notify(){ //当改变之后每次都调用一次这个方法
this.reactiveFns.forEach(fn=>{
fn()
})
}
}
const depend = new Depend()
function watchFn(fn){ //设置一个函数来判断哪些函数需要是响应式
depend.addDepend(fn)
}
watchFn(function(){
console.log(objProxy.name) //缺点为仅监听了name属性的变化
})
watchFn(function(){
console.log(objProxy.age)
})
const obj = {
name:'xi',
age:20
}
const objProxy = new Proxy(obj,{
get:function(target,key,recevier){
return Reflect.get(target,key,recevier)
}
set:function(target,key,newValue,recevier){
Reflect.set(target,key,newValue,recevier)
depend.notify() //此时只要设置了代码这个就会自动执行一次
}
})
优化
const targetMap = new WeakMap()
function getDepend(target,key){
//根据target对象获取map
let map = targetMap.get(target)
if(!map){
map = new Map()
targetMap.set(target,map)
}
//根据key获取depend对象
let depend = map.get(key)
if(!depend){
depend = new Depend()
map.set(key,depend)
}
return depend
}
const objProxy = new Proxy(obj,{
get:function(target,key,recevier){
return Reflect.get(target,key,recevier)
}
set:function(target,key,newValue,recevier){
Reflect.set(target,key,newValue,recevier)
const depend = getDepend(target,key)
depend.notify() //此时只要设置了代码这个就会自动执行一次
}
})
优化二-收集依赖
let activeReactiveFn = null
function watchFn(fn){ //设置一个函数来判断哪些函数需要是响应式
activeReactiveFn = fn
//默认添加时会执行一次,执行会调用Proxy对象,所以会在get中执行一次,添加对应的依赖
fn()
activeReactiveFn = null
}
//监听对象的属性变量:Proxy(Vue3)/Object.defineProperty(Vue2)
const objProxy = new Proxy(obj,{
get:function(target,key,recevier){
//根据target,key获取对应的depend
const depend = getDepend(target,key)
//给depend对象添加响应函数
depend.addDepend(activeReactiveFn)
return Reflect.get(target,key,recevier)
}
set:function(target,key,newValue,recevier){
Reflect.set(target,key,newValue,recevier)
const depend = getDepend(target,key)
depend.notify() //此时只要设置了代码这个就会自动执行一次
}
})
优化三
class Depend {
constructor(){
this.reactiveFns = new Set() //去重。存在一个fn之后不会再进行
}
depend(){
if(activeReactiveFn){
this.reactiveFns.add(activeReactiveFn)
}
}
notify(){ //当改变之后每次都调用一次这个方法
this.reactiveFns.forEach(fn=>{
fn()
})
}
}
const objProxy = new Proxy(obj,{
get:function(target,key,recevier){
//根据target,key获取对应的depend
const depend = getDepend(target,key)
//给depend对象添加响应函数
depend.depend()
return Reflect.get(target,key,recevier)
}
set:function(target,key,newValue,recevier){
Reflect.set(target,key,newValue,recevier)
const depend = getDepend(target,key)
depend.notify() //此时只要设置了代码这个就会自动执行一次
}
})
优化四 对所有对象进行
function reactive(obj){
return new Proxy(obj,{
get:function(target,key,recevier){
//根据target,key获取对应的depend
const depend = getDepend(target,key)
//给depend对象添加响应函数
depend.depend()
return Reflect.get(target,key,recevier)
}
set:function(target,key,newValue,recevier){
Reflect.set(target,key,newValue,recevier)
const depend = getDepend(target,key)
depend.notify() //此时只要设置了代码这个就会自动执行一次
}
})
}
//之后所有的对象都开始使用reactive'创建一个代理对象
const foo={name:'k',age:30}
const fooProxy = reactive(foo)
Vue2响应式原理
function reactive(obj){
Object.keys(obj).forEach(key=>{
let value = obj[key]
Object.defineProperty(obj,key,{
get:function(){
const depend = getDepend(obj,key)
depend.depend()
return value
}
set:function(newValue){
value = newValue
const depend = getDepend(obj,key)
depend.notify()
}
})
})
}