使用Proxy 监听对象属性值变化

单层监听

只监听对象单层的属性变化。目前没有对map、set等类型的数据做监听,后续慢慢更新。

//监听对象属性值是否发生改变,对象属性数量是否变化
//参数: object 要代理的对象名称,
// callback: {
//     //getter 对象访问属性时会出发,如果此方法没有返回值,则返回对象属性本生的值。
//     onGet: function(object, property) {
//         //object:代理后的对象,
//         //property:访问的属性。
//     },
//     //setter 对象属性赋值时会触发方法。
//     onSet: function(object, property, value) {
//         //object:代理后的对象,
//         //property:访问的属性。
//         //value:设置的值
//     },
//     onProtertyNumChage: function(object) {
//         //object:代理后的对象,
//         //property:访问的属性。
//     }
// }
class ObjectListener {
	constructor(object, callback, config) {
		this.object = object
		//声明自定义方法
		this.callback = {
			onGet: function (object, property) {},
			onSet: function (object, property, value) {},
			onProtertyNumChage: function (object) {}
		}
		//默认值
		this.callback.onGet = callback.onGet || this.callback.onGet
		this.callback.onSet = callback.onSet || this.callback.onSet
		this.callback.onProtertyNumChage = callback.onProtertyNumChage || this.callback.onProtertyNumChage

		//声明触发配置
		this.config = {
			enableOnSetWhenKyesChange: false,
			//添加属性时不再触发onSet
			enableOnProtertyNumChage: true
			//添加属性时触发OnProtertyNumChage,如果此项为False,则只会触发onSet并且覆盖enableOnSetWhenKyesChange配置
		}
		if (config) {
			this.config.enableOnSetWhenKyesChange = Reflect.has(config, "enableOnSetWhenKyesChange") ? config.enableOnSetWhenKyesChange : this.config.enableOnSetWhenKyesChange
			this.config.enableOnProtertyNumChage = Reflect.has(config, "enableOnProtertyNumChage") ? config.enableOnProtertyNumChage : this.config.enableOnProtertyNumChage
		}

		this.Proxys = new Proxy(object, this.iinterceptor)

		this.objKeys = Object.keys(this.object).length //用于判断对象属性数量是否发生变化
		Object.defineProperty(this, "num", {
			set(value) {
				this.objKeys = value
				this.callback.onProtertyNumChage(this.Proxys)
			},
			get() {
				return this.objKeys
			}
		})

		return this.Proxys
	}

	iinterceptor = {
		//将父级对象传值到此对象
		_parent_: this,

		set: function (object, property, value) {
			object[property] = value
			//监听对象属性数量是否发生变化

			if (Object.keys(object).length !== this._parent_.num && this._parent_.config.enableOnProtertyNumChage) {
				this._parent_.num = Object.keys(object).length
				if (!this._parent_.config.enableOnSetWhenKyesChange) return value
			}

			//如果onSet没有返回值,则对象赋值值为vlaue
			object[property] = this._parent_.callback.onSet(this._parent_.Proxys, property, value) || value
			return value
		},
		get: function (object, property) {
			if (property === "num") {
				return this._parent_.objKeys
			}
			return this._parent_.callback?.onGet(object, property) || object[property]
		}
	}
}

调用

//	object === objectListener 都是代理后的对象
	let objectListener= new ObjectListener(targetObject, {
		onGet: function (object, property) {
			console.log('onGet')
		},
		onSet: function (object, property, value) {
			console.log('onSet')
		},
		onProtertyNumChage: function (object) {
			console.log("onProtertyNumChage");
		}
	}, {
		enableOnSetWhenKyesChange: false,//添加属性时不再触发onSet
		enableOnProtertyNumChage: true//添加属性时触发OnProtertyNumChage,如果此项为False,则只会触发onSet并且覆盖enableOnSetWhenKyesChange配置
	})

深度监听

在单层监听的基础上,做递归操作。便利对象,如果属性为对象,则使用代理并且把代理后的对象赋值到当前对象的相应属性下。

class ObjectListenerDeep {
	constructor(object, callback) {
		this.deepRecording = null
		this.object = object
		//声明自定义方法
		this.callback = {
			onGet: function (object, property) {},
			onSet: function (object, property, value) {},
			onProtertyNumChage: function (object) {}
		}
		//默认值
		this.callback.onGet = callback.onGet || this.callback.onGet
		this.callback.onSet = callback.onSet || this.callback.onSet
		this.callback.onProtertyNumChage = callback.onProtertyNumChage || this.callback.onProtertyNumChage

		//声明触发配置
		this.config = {
			enableOnSetWhenKyesChange: false,
			//添加属性时不再触发onSet
			enableOnProtertyNumChage: true
			//添加属性时触发OnProtertyNumChage,如果此项为False,则只会触发onSet并且覆盖enableOnSetWhenKyesChange配置
			//深度监听时,增加和删除属性会出现判断错误,默认为flase
			//所有的新增和修改都会触发set,因此不再提供可配置项
		}
		if (config) {
			this.config.enableOnSetWhenKyesChange = Reflect.has(config, "enableOnSetWhenKyesChange") ? config.enableOnSetWhenKyesChange : this.config.enableOnSetWhenKyesChange
			this.config.enableOnProtertyNumChage = Reflect.has(config, "enableOnProtertyNumChage") ? config.enableOnProtertyNumChage : this.config.enableOnProtertyNumChage
		}
		this.objectEach()
		return this.deepRecording
	}
	objectEach() {
		let _this = this
		function traverse(object) {
			for (const key in object) {
				if (Object.hasOwnProperty.call(object, key)) {
					const element = object[key]
					if (typeof element === "object" && !Array.isArray(element)) {
						traverse(element)
						object[key] = _this.newObjectListener(element)
					}
				}
			}
		}
		this.deepRecording = _this.newObjectListener(_this.object)
		traverse(_this.object)
		// this.object
	}
	newObjectListener(object) {
		let _this = this
		return new ObjectListener(
			object,
			{
				onGet: _this.callback.onGet,
				onSet: _this.callback.onSet,
				onProtertyNumChage: _this.callback.onProtertyNumChage
			},
			{
				enableOnSetWhenKyesChange: _this.config.enableOnSetWhenKyesChange,
				enableOnProtertyNumChage: _this.config.enableOnProtertyNumChage
			}
		)
	}
}

调用

	let saveDataListener2 = new ObjectListenerDeep(targetObject, {
		onGet: function (object, property) {
			//console.log('get', property, object)
		},
		onSet: function (object, property, value) {
			//console.log('set', property, value, object)
		}
	})

代码还很简陋,仅仅作为一个学习记录。
发现一个问题,在封装的回调中不能多次赋值否则会循环调用导致爆栈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值