Proxy-Reflect的学习

43 阅读3分钟

Proxy-Reflect的学习

监听对象属性的操作一

const obj = {
  name: 'Fhup',
  age: 18
}

Object.keys(obj).forEach(item => {
  
  let value = obj[item]
  // 通过Object.defineProperty()对对象属性进行操作
  Object.defineProperty(obj, item, {
    configurable: true,
    enumerable: true,
    get() {
      console.log(`监听${item}获取值~`);
      return value
    },
    set(newValue) {
      console.log(`监听${item}设置值~`);
      value = newValue
    }
  })
})

obj.name = '123'
obj.age = 3
console.log(obj.name);
console.log(obj.age);

// 缺点
// 1.Object.defineProperty()设计初衷,不是为了监听截止一个对象的的属性
// 2.新增属性,删除属性, Object.defineProperty()无能为力

// Proxy解决了上面的缺点

Proxy监听对象属性操作二

/**
 * ES6: 新增Proxy类. 用于创建一个代理.
 * 监听一个对象的相关操作.可以先创建一个代理对象(Proxy对象)
 * 之后对该对象的所有操作,通过代理对象完成
 */
const obj = {
  name: 'Fhup',
  age: 18
}
// 参数2: 传入捕获器
const objProxy = new Proxy(obj, {
  // 1.获取值时的捕获器
  get(target, key) {// target:代理的对象obj, key: 对象的属性.
    console.log(`获取obj的${key}~`);
    return target[key]
  },
  // 2.设置值时的捕获器
  set(target, key, newValue) {// target:代理的对象obj, key: 对象的属性, newValue: 设置的新值
    console.log(`设置obj的${key}~`);
    target[key] = newValue
  }
})

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

objProxy.name = 'xxx'
objProxy.age = 3


console.log(obj);
console.log(objProxy);

Proxy其他的捕获器

let obj = {
  name: 'Fhup',
  age: 18
}
const objProxy = new Proxy(obj, {
  set(target, key, newValue){
    console.log('设置值')
    target[key] = newValue
  },
  get(target, key){
    console.log('获取值')
    return target[key]
  },

  // 监听in的捕获器
  has(target, key) {
    console.log('监听in操作')
    return key in target // 默认返回false
  },
  // 监听delete的捕获器
  deleteProperty(target, key){
    console.log('监听delete操作');
    delete target[key]
  }
})

// in操作符 ( 判断objProxy中的key有没有 'age' 属性 )
console.log('age' in objProxy) // true

// delete操作
delete objProxy.age

console.log(obj)

Proxy对函数对象的监听

function foo() {
  
}
let fooProxy = new Proxy(foo, {
  // 用apply来调用触发的捕获器
  apply(target, thisArg, argArray) {
    console.log('apply调用~');
    return target.apply(thisArg, argArray)
  },
  // 用new来调用创建的捕获器
  construct(target, argArray, newTarget) {
    console.log('new调用~');
    return new target(...argArray)
  }
})

new fooProxy()

fooProxy.apply(this,[])

Reflect和Proxy的结合使用

/**
 * Reflect: ES6新增,是一个[对象],字面意思是反射.
 * 主要提供了 操作JS对象的方法,有点像 Object操作对象的方法
 * Reflect.defineProperty() 类似于 Object.defineProperty()
 * Reflect常见的方法与Proxy中的捕获器方法一一对应(13个)
 */
const obj = {
  name: 'Fhup',
  age: 18
}
const objProxy = new Proxy(obj, {
  // 捕获器
  set(target, key, newValue){
    console.log('设置值~');
    Reflect.set(target, key, newValue) // 返回Boolean值,判断是否设置成功
  },
  get(target, key){
    console.log('获取值~');
    return Reflect.get(target, key)
  }
})

objProxy.name = 'xxx'
objProxy.age = 3

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

console.log(objProxy)
console.log(obj)

捕获器中receiver参数

const obj = {
  _name: 'Fhup',
  get name() {
    return this._name
  },
  set name(newValue) {
    this._name = newValue
  }
}
/**
 * 注意: 只有get()和set()有receiver
 * receiver的作用是 改变this指向
 */
const objProxy = new Proxy(obj, {
  get(target, key, receiver) {
    // receiver就是创建出来的代理对象objProxy
    // key值为name  receiver为 Proxy {_name: 'xxx'}  true
    console.log('获取------', key, receiver, receiver === objProxy)
    // 执行 Reflect.get() 会去找obj对象的get name(){},将 get name(){}的 this 赋值为 receiver
    // receiver._name就成为代理对象的属性, 然后 name 和 _name 都会被捕获到
    return Reflect.get(target, key, receiver)
  },
  set(target, key, newValue, receiver) {
    console.log('设置------', key);
    Reflect.set(target, key, newValue, receiver)
  }
})

objProxy.name = 'xxx'
console.log(objProxy.name)

/**
 * Proxy()和Reflect结合时,使用receiver更佳!
 * 而receiver还可以传入其他的值.操作意义不大
 */

Reflect中construct作用

function Student(name, age) {
  this.name = name
  this.age = age
}
function Teacher() {

}

// const stu = new Student('Fhup', 18)
// console.log(stu) // Student { name: 'Fhup', age: 18 }

// 需求: 执行Student函数的内容,但是创建出来对象是Teacher对象
const teacher = Reflect.construct(Student, ['Fhup', 18], Teacher)
console.log(teacher) // Teacher { name: 'Fhup', age: 18 }
console.log(teacher.__proto__ === Teacher.prototype) // true
// 创建Teacher对象,内部执行Student函数的内容 (内部实现: 变换this指向)