defineProperty如何实现数据代理

95 阅读1分钟

Object.defineProperty()

1. 基本使用

语法:Object.defineProperty(obj, key, descriptor:属性和方法)

obj:要进行操作的对象。

key:要定义或修改的属性的名称。

let obj = {}
Object.defineProperty(obj,'a',{
    configurable: true    //是否允许删除
    enumerable:true      //是否允许枚举
    value:undefined      //就是value值
    writable:true        //是否允许赋值   
    
    get() {}    //获取的return的值
    set(val) {}    //修改的时候执行  val就是最新的值
})
使用
 let obj = {
        name: "张三",
        age: 21
    }

    let keys = Object.keys(obj);
    for (let i in keys) {
        let key = keys[i];
        Object.defineProperty(obj, key, {
            get() {
                return obj[key];
            },
            set(val) {
                obj[key] = val;
            }
        })
    }

    obj.name = "李四";

看起来感觉上面的代码没有什么错误,但是试着运行一下吧~你会和我一样栈溢出。这是为什么呢?让我们聚焦在set方法里,我们在修改obj身上的name属性时,会触发set方法,set方法里又继续修改obj属性的值,导致递归调用,最终栈溢出。

这也引出了我们下面的方法,我们需要设置一个中转data,来让set修改data的值,get在返回出data的属性值。

而不是直接修改obj导致导致递归调用。

 	let obj = {
        name: "张三",
        age: 21
    }
    let data = {}

    let keys = Object.keys(obj);
    for (let i in keys) {
        let key = keys[i];
        Object.defineProperty(obj,key,{
            get() {
                return data[key];
            },
            set(val) {
                data[key] = val;
            }
        })
    }

    obj.name = "李四"
监听对象上的多个属性

在实际情况中,我们通常需要一次监听多个属性的变化。这时我们需要配合Object.keys(obj)进行遍历。这个方法可以返回obj对象身上的所有可枚举属性组成的字符数组。下面是该API一个简单的使用效果:

let obj = {  name: "张三", age: 21 };
console.log(Object.keys(obj)); // console: ['name', 'age'];