let obj = {
name:'ll',
age:18
}
Object.keys(obj).forEach(key=>{
let value = obj[key]
Object.defineProperty(obj,key,{
get:function () {
console.log('监听到访问'+key);
return value
},
set:function(newVal){
console.log('监听到设置' + key);
value = newVal
}
})
})
obj.name = 'kk'
obj.age = 30
console.log(obj.name);
console.log(obj.age);
Object.defineProperty :设计的初衷不是监听对象属性,而是定义属性,如果想监听更多的操作比如新增属性,删除属性,Object.defineProperty是无能为力的
proxy :es6新增类,帮我们创建一个代理,如果想监听对象的操作,先创建一个代理,然后对对象所有操作都通过代理完成,代理可以监听我们对原对象的操作
let obj = {
name: 'll',
age: 18
}
// const objProxy = new Proxy(obj,捕获器对象)
const objProxy = new Proxy(obj, {
// 重写捕获器
// 获取值时捕获器
get: function (target, key, receiver) {
// receiver 调用的代理对象
// target 就是 目标对象(obj)
console.log('监听到访问' + key,target);
return target[key]
},
// 设置值时捕获器
set: function (target,key,newVal,receiver) {
console.log('监听到设置' + key,target);
target[key] = newVal
}
})
objProxy.name = 'kk'
objProxy.age = 30
console.log(objProxy.name);
console.log(objProxy.age);
如果想监听具体操作需要在 handle中添加对应的捕获器Trap
let obj = {
name: 'll',
age: 18
}
const objProxy = new Proxy(obj, {
// 监听 in 捕获器
has: function (target, key) {
console.log('监听in操作' + key, target)
return key in target
},
//
deleteProperty:function(target, key) {
console.log('监听delete操作' + key, target)
delete target[key]
},
})
// in操作符
console.log('name' in objProxy);
// delete 操作
delete objProxy.name
console.log(objProxy);
proxy 一共有13种捕获器
应用于函数对象: 函数调用/new 操作符的捕获器
function foo() {
}
const fooProxy = new Proxy(foo,{
// 监听apply调用
apply:function(target,thisArg,argArray){
console.log('监听apply');
return target.apply(thisArg,argArray)
},
// new 操作符
construct: function (target,argArray,newTarget) {
console.log('监听new');
return new target(...argArray)
}
})
// foo()
// apply调用
fooProxy.apply({},['abc','cba'])
// new调用
new fooProxy('abc','cba')
reflect作用:es6新增api,是一个对象,反射的意思
作用: 提供了操作js对象的方法,Reflect.getPrototypeOf(target)类似 Object.getPrototypeOf
Reflect.defineProperty( target,propertyKey,attributes)类似Object..defineProperty()
早期因为考虑不周全,把没有考虑的一些api都塞到object中,后面考虑到放object里面不合适,然后新增其他的属性(in delete 操作符让js看起来很怪)
Reflect和object 区别:比较 Reflect 和 Object 方法 - JavaScript | MDN
receiver作用:
const obj = {
_name:'why',
get name(){
// 这里的this 指的是obj
return this._name
// 这里访问不到objProxy的get方法 绕过objProxy直接访问obj的_name ,不能满足所有访问都经过代理
},
set name(newVal){
this._name = newVal
}
}
const objProxy = new Proxy(obj,{
get:function(target,key){
console.log('触发了get方法',key );
return Reflect.get(target,key) // 去上面的get
},
set:function(target,key,newVal){
Reflect.set(target,key,newVal)
}
})
console.log(objProxy.name,'name');
只有name走了代理,_name 访问没走 (无法拦截)
因为this指向obj ,如果让this指向objProxy,就会经过get(objProxy的)
receiver 的意义就来了,是创建的代理对象,可以拦截所有属性
const obj = {
_name:'why',
get name(){
// 这里的this 指的是obj
return this._name
// 这里访问不到objProxy的get方法 绕过objProxy直接访问obj的_name ,不能满足所有访问都经过代理,加上receiver this指向objProxy
},
set name(newVal){
this._name = newVal
}
}
const objProxy = new Proxy(obj,{
get:function(target,key,receiver){
console.log('触发了get方法',key );
return Reflect.get(target,key,receiver) // 去上面的get
},
set:function(target,key,newVal,receiver){
Reflect.set(target,key,newVal,receiver)
}
})
console.log(objProxy.name,'name');
reflect中construct的作用:
function Student(name,age) {
this.name = name;
this.age = age;
}
function Teacher() {
}
// 执行student函数内容,创建出来是teacher对象
const teacher = Reflect.construct(Student,['why,18'],Teacher)
console.log(teacher,'teacher');
console.log(teacher.__proto__===Teacher.prototype );
响应式:
大白话: MM有一个初始化的值,有一段代码用到了这个值,那么在MM有一个新值,这段代码可以自动重新执行(相关代码都自动执行)
let m = 100 // m发生变化下面的代码自动执行
//一段代码
console.log(m);
console.log(m*2);
vue3 响应式的粗糙实现
// 封装响应式函数
let activeReactiveFn = null
// 收集所有属性的依赖
class Depend {
constructor(){
// 用set 避免重复
this.reactiveFns = new Set()
}
depend(){
if(activeReactiveFn){
this.reactiveFns.add(activeReactiveFn)
}
};
notify(){
this.reactiveFns.forEach(fn => {
fn()
})
}
}
// 封装一个响应式函数
// const depend = new Depend()
function watchFn (fn){
activeReactiveFn = fn
fn()
// 用完销毁
activeReactiveFn = null
}
// 正确收集依赖
//封装一个获取depend函数
const targetMap = new WeakMap()
// 依赖收集的数据结构
function getDepend (target,key){
// 获取对应depend
let map = targetMap.get(target,key)
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
}
function reactive(obj) {
return new Proxy(obj, {
// 获取值的捕获器
get: function (target, key, receiver) {
// 根据target,key获取对应的depend
const depend = getDepend(target, key)
// 给depend对象添加函数
depend.depend()
return Reflect.get(target, key, receiver);
},
// 设置值的捕获器
set: function (target, key, newVal, receiver) {
Reflect.set(target, key, newVal, receiver);
const depend = getDepend(target, key)
depend.notify()
},
});
}
const obj = {
name:'wy', //一个属性对应一个dep对象
age:18 ,
}
// 监听属性变化,自动执行notify
const objProxy = reactive(obj)
watchFn(function () {
console.log('我是 name', objProxy.name);
});
watchFn(function () {
console.log('我是 age', objProxy.age);
})
objProxy.name = 'pp'
const infoProxy =reactive({
address: 'tianjin'
})
watchFn(function () {
console.log(infoProxy.address,'监听地址的变化');
})
infoProxy.address = 'beijing'