赞
踩
监听对象的属性变化,可以使用Object.defineProperty、Proxy等
如果您还不了解Object.defineProperty, 您可以先查看 深入了解Object.defineProperty 来了解。
let obj = { } let val = obj.name; Object.defineProperty(obj, 'name', { // 存储描述符的方法来定义对象属性 set(newVal){ console.log("检测到了数据的变化",newVal) val = newVal; }, get(){ return val } }); setTimeout(() => { // 显然当对象的属性重新赋值(发生变化)时,会触发set方法,检测到数据的变化 obj.name = 'a';
function observe(obj){ if(!obj || typeof obj != 'object'){ return } //每一层对象都绑定getter和setter for(var i in obj){ definePro(obj,i,obj[i]); } } function definePro(obj,key,value){ //递归调用 observe(value); object.defineProperty(obj,key,{ get: function(){ return value;}, set: function(newVal){ console.log("检测到了数据的变化",newVal); value = newVal } }) } var obj = {"a": {"name": {"fname": "Zi", "Mname": "Y"}, "age": 18}} observe(obj)
Object.defineProperty无法监听数组对象上原型方法,包括push, pop, shift, unshift, splice, sort, reverse等
var arrayProto = Array.prototype var arrayMethods = Object.create(arrayProto) /** Object.create(proto[,properties]) * Object.create()方法创建了一个新对象,使得现有的对* 象来提供新创建的对象的__proto__ * 即:arrayMethods.__proto__ == Array.prototype //true * arrayMethods.constructor == Array // true */ [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ].forEach(function(item){ Object.defineProperty(arrayMethods,item,{ value:function mutator(){ //缓存原生方法,之后调用 console.log('array被访问'); /** * original是arrayMethods 原型上的方法 * 这里把item用Obejct.defineProperty写到arrayMethods上 * 因此但凡用到了arrayMethods.item就会被检测到 * 这里以push为例,item取push arrayMethods.push是一个function * 所传的参数arrayMethods.push(3) 3为arguments */ var original = arrayProto[item] var args = Array.from(arguments) //调用原型上的方法执行。 original.apply(this,args) // console.log(this); }, }) }) arrayMethods.push(2)
Object.defineProperty不能直接监听数组的变化,而Proxy可以。
官方文档 MDN 上 Proxy的定义: Proxy对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)
语法
const p = new Proxy(target,handler)
target: 要使用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理p的行为。
const handler = {
get: function(obj,prop){
return prop in obj ? obj[prop]: '数据不存在!'
}
}
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined
console.log(p.c) // '数据不存在'
Proxy既能够监听到对象属性的变化,也能监听到数组的操作。
在使用Proxy前您可以先了解Reflect
var observe = (object)=>{ const handler = { get(target,property,receiver){ try{ return new Proxy(target[property],handler); }catch(err){ return Reflect.get(target,property,receiver) } }, set(target,key,value,receiver){ console.log("===检测到了变化"); return Reflect.set(target,key,value,receiver); } }; return new Proxy(obj,handler) }; var obj = { foo:false, a:{ x:{ y:4},b:[{c:false}]} } var test = observe(obj) test.a.x.y = 5 // ===检测到了变化 test.a.b.push("mm") // ===检测到了变化 //此时,test.a.b打印出来的结果Proxy{0:{c:false},1:'mm'} 说明它是个类数组
test.a.x.y = 5 // ===检测到了变化
//查找y属性时,调用getter访问器,返回x[y]
test.a.b.push("mm") // ===检测到了变化
//.push(),调用setter访问器, 原来b:Proxy{0:{c: false}},push后 key为1,
// 即Reflect.set(b,1,,"mm") 结果b:Proxy{0:{c:false},1:'mm'}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。