当前位置:   article > 正文

如何监听一个对象所有属性的变化_监听对象属性变化

监听对象属性变化

监听对象的属性变化,可以使用Object.defineProperty、Proxy等
如果您还不了解Object.defineProperty, 您可以先查看 深入了解Object.defineProperty 来了解。

Object.definedProperty

1. 1 使用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';
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
1. 2 深度监听对象属性
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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
1. 2 监听数组的方法

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

Proxy

1.1 Proxy的定义

Object.defineProperty不能直接监听数组的变化,而Proxy可以。
官方文档 MDN 上 Proxy的定义: Proxy对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)

语法
const p = new Proxy(target,handler)

target: 要使用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理p的行为。
  • 1
  • 2
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)  // '数据不存在'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
1.2 Proxy监听对象属性的变化

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'} 说明它是个类数组
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
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'}
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/55944
推荐阅读
相关标签
  

闽ICP备14008679号