JS监听对象的操作

1,589 阅读2分钟

方法一 Object.defineProperty

使用Object.defineProperty 的存储属性描述符来对属性的操作进行监听 举例代码:

const obj = {
  name: "why",
  age: 18
}
Object.keys(obj).forEach(key => {
  let value = obj[key]

  Object.defineProperty(obj, key, {
    get: function() {
      console.log(`监听到obj对象的${key}属性被访问了`)
      return value
    },
    set: function(newValue) {
      console.log(`监听到obj对象的${key}属性被设置值`)
      value = newValue
    }
  })
})

obj.name = "kobe"
obj.age = 30

console.log(obj.name)
console.log(obj.age)

obj.height = 1.88

// 以上代码打印结果如下
// 监听到obj对象的age属性被设置值
// 监听到obj对象的name属性被访问了
// kobe
// 监听到obj对象的age属性被访问了
// 30

缺点:如果我们想监听更加丰富的操作,比如新增属性、删除属性,那么Object.defineProperty是无能为力的。而且这种方法改变了数据的属性 name和age的属性描述符从数据属性描述符变成了访问属性描述符。

方法二 Proxy

ES6中,新增了一个Proxy类,是用于帮助我们创建一个代理的: 如果我们希望监听一个对象的相关操作,那么我们可以先创建一个代理对象(Proxy对象),之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些操作。

Proxy共有13个捕捉器

image.png 使用Proxy的set和get捕获器可以监听对象的设置和获取操作 示例代码如下:

const obj = {
  name: "why",
  age: 18
}

const objProxy = new Proxy(obj, {
  // 获取值时的捕获器
  get: function(target, key) {
    console.log(`监听到对象的${key}属性被访问了`, target)
    return target[key]
  },

  // 设置值时的捕获器
  set: function(target, key, newValue) {
    console.log(`监听到对象的${key}属性被设置值`, target)
    target[key] = newValue
  }
  
  // 监听in的捕获器
  has: function(target, key) {
    console.log(`监听到对象的${key}属性in操作`, target)
    return key in target
  },

  // 监听delete的捕获器
  deleteProperty: function(target, key) {
    console.log(`监听到对象的${key}属性in操作`, target)
    delete target[key]
  }
})

console.log(objProxy.name)
console.log(objProxy.age)

objProxy.name = "kobe"
objProxy.age = 30

console.log(obj.name)
console.log(obj.age)

// in操作符
console.log("name" in objProxy)

// delete操作
delete objProxy.name

// 以上代码运行结果
// 监听到对象的name属性被访问了 { name: 'why', age: 18 }
// why
// 监听到对象的age属性被访问了 { name: 'why', age: 18 }
// 18
// 监听到对象的name属性被设置值 { name: 'why', age: 18 }
// 监听到对象的age属性被设置值 { name: 'kobe', age: 18 }
// kobe
// 30
// 监听到对象的name属性in操作 { name: 'why', age: 18 }
// true
// 监听到对象的name属性delete操作 { name: 'why', age: 18 }

set和get分别对应的是函数类型;

set函数有四个参数:

  • target:目标对象(侦听的对象);
  • property:将被设置的属性key;
  • value:新属性值;
  • receiver:调用的代理对象; get函数有三个参数:
  • target:目标对象(侦听的对象);
  • property:被获取的属性key;
  • receiver:调用的代理对象;