一、监听对象的操作
(一)利用Object.defineProperty
属性描述符监听对象被设置或修改的过程
let obj = {
name: 'why',
age: 18
}
Object.keys(obj).forEach(key => {
Object.defineProperty(obj, key, {
get() {
console.log(`监听到obj对象的${key}属性被访问了`);
},
set() {
console.log(`监听到obj对象的${key}属性被设置值`);
}
})
})
obj.name = 'noWhy'; //监听到obj对象的name属性被设置值
//监听到obj对象的name属性被设置值
//监听到obj对象的name属性被访问了
//undefined
console.log(obj.name);
此时更改name值为noWhy,打印obj.name则为undefined,需要打印具体值应做以下操作
let obj = {
name: 'why',
age: 18
}
Object.keys(obj).forEach(key => {
let value = obj[key]
Object.defineProperty(obj, key, {
get() {
return value
console.log(`监听到obj对象的${key}属性被访问了`);
},
set(newValue) {
value = newValue
console.log(`监听到obj对象的${key}属性被设置值`);
}
})
})
obj.name = 'noWhy'; //监听到obj对象的name属性被设置值
//监听到obj对象的name属性被设置值
//监听到obj对象的name属性被访问了
//noWhy
console.log(obj.name);
缺点:
Object.defineProperty
设计的初衷是为了定义对象中的属性描述符(对象属性是否可枚举、是否可写入等等),其次无法监听新增属性、删除属性
(二)Proxy
Proxy()
通过Proxy代理对象捕获代理对象所做的操作,例如属性查找、赋值、枚举、函数调用等。
const proxy = new Proxy(target, handler);
target
: 对某个对象进行代理handler
: 捕获器对象,捕获对当前对象的一系列操作
1. Proxy对对象的监听
const obj = {
name: 'why',
age: 18
}
const objProxy = new Proxy(obj,{
//get:监听获取对象
//target:所代理的对象
//key:所操作的属性的key
get(target, key){
console.log(target); //{name: 'why', age: 18}
console.log(target[key]); //why
return target[key];
},
//set:监听对象属性被修改
//target:所代理的对象
//key:所操作的属性的key
//newValue:新设置的值
set(target, key, newValue){
console.log(newValue); //22
target[key] = newValue
},
//监听对象属性被删除
deleteProperty(target, key){
console.log('11111');
delete target[key]
},
//监听in的捕获器
has(target, key){
console.log(`监听到对象的${key}属性的in操作`);
return key in target
}
})
let a = objProxy.name;
objProxy.age = 22
delete objProxy.name
console.log("name" in objProxy); //in检测一个属性是否为该对象成员
2.Proxy对函数的监听
function foo(){}
const fooProxy = new Proxy(foo, {
apply(target, thisArg, argArray){
console.log('对foo函数进行了apply调用');
return target.apply(thisArg, argArray)
},
construct(target, argArray){
console.log('对foo函数进行了new调用');
return new target(...argArray)
}
})
fooProxy.apply({}, ['abc', 'cba'])
new fooProxy('abc', 'cba')
(三)Reflect
Reflect
类似于Object.getPrototypeOf操作符,如浏览器支持情况下可将Object换成Reflect.getPrototypeOf
const obj = {
name: 'why',
age: 18
}
const objProxy = new Proxy(obj, {
get(target, key) {
// return target[key];
return Reflect.get(target, key)
},
set(target, key, newValue) {
// target[key] = newValue
Reflect.set(target, key, newValue)
},
})
objProxy.name = "noWhy"
console.log(objProxy.name);
二、响应式原理
用vue举例,当data中属性值改变,dom元素绑定的数值也会随之data改变而改变
{{ value }}
- 当obj的值发生改变时,相应的响应式函数也会触发响应
const obj = {
name: 'why',
age: 18
}
//封装一个响应式的函数
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('11111');
})
watchFn(function (){
console.log('22222');
})
const objProxy = new Proxy(obj, {
get(target, key){
return Reflect.get(target, key)
},
set(target, key, newValue){
Reflect.set(target, key, newValue)
depend.notify()
}
})
objProxy.name = 'noWhy'