JavaScript 中的 Proxy Reflect API 基本使用介绍

在 JavaScript 中,代理(Proxy)对象和反射(Reflect)API 提供我们一个强大的能力—控制和修改对象的基本行为。它们通常用于创建各种抽象,如数据绑定、象征性(symbolic)计算。此 API 也应用于 Vue3 框架中。

1. Proxy API

使用语法:

const proxyObject  = new Proxy(target, handler)

参考以下代码示例:

const P = {
  a: 'a',
}

const proxyObject = new Proxy(P, {
  // proxyObject.propertyName、
  // Object.getOwnPropertyDescriptor(proxyObject, 'propertyName')
  // 或者Reflect.get(proxyObject, 'propertyName')
  // get陷阱函数会被触发。
  get(target, property) {
    debugger;
    console.log('触发get');
    return property in target ? target[property] : null
  },
  defineProperty(target, property, attrs) {
    // 使用 Object.defineProperty(proxyObject, 'x',{}) 触发
    throw new Error('不允许修改')
  },
  deleteProperty(target, property) {
    // delete proxyObject.xx 、
    // Reflect.deleteProperty(proxyObject, 'propertyName') 触发
    console.log('触发deleteProperty');
    delete target[property]
  },
  set(target, property, value) {
    // proxyObject.xx 、
    // Object.defineProperty()或Reflect.set() 触发
    console.log('触发set');
    target[property] = value
  },
})


P.c = 'c' // 原对象新增一个属性
proxyObject.d = 'd' // -> 触发 set
hhh = proxyObject.a // -> 触发 get
delete proxyObject.a // -> 触发 deleteProperty
Reflect.deleteProperty(proxyObject, 'd') // -> 触发 deleteProperty

// 下方代码将抛出一个错误
// Object.defineProperty(proxyObject,'n',{
//   value: 123,
//   writable: false,
//   enumerable: false,
//   configurable: false,
// })
console.log('ooo', P)
console.log('ppp', proxyObject);

2. Reflect API

Reflect 对象主要包含以下的静态函数:

1. Reflect.apply(target, thisArgument, argumentsList)

调用一个目标函数,并指定 this 值和参数列表。

let numbers = [1, 2, 3, 4, 5]
let max = Reflect.apply(Math.max, Math, numbers)
console.log(max)  // 输出 5

2. Reflect.construct(target, argumentsList[, newTarget])

等同于 new target(...args) 的操作,允许改变实例化对象时的原型。

function MyDate(...args) {
  return new Date(...args)
}

let instance = Reflect.construct(MyDate, [2022, 0, 1])
console.log(instance instanceof MyDate)  // Outputs: false
console.log(instance instanceof Date)    // Outputs: true

3. Reflect.defineProperty(target, propertyKey, attributes)

基本等同于 Object.defineProperty ,会返回一个表示定义成功或失败的布尔值,不是抛出错误。

let obj = {}
let result = Reflect.defineProperty(obj, 'prop', { value: 1 })
console.log(result)  // 输出:true
console.log(obj.prop)  // 输出:1

4. Reflect.deleteProperty(target, propertyKey)

删除对象的属性,操作成功返回 true,否则返回 false

let obj = { prop: 1 }
let result = Reflect.deleteProperty(obj, 'prop')
console.log(result)  // 输出:true
console.log(obj.prop)  // 输出:undefined

除此之外,Reflect对象还有诸如 Reflect.get(), Reflect.set(), Reflect.has(), Reflect.ownKeys(), Reflect.isExtensible(), Reflect.preventExtensions(), Reflect.getPrototypeOf(), Reflect.setPrototypeOf() 等等方法。

3. Proxy API 的使用场景

  1. 数据验证和保护:
const data = {
  name: 'John',
  age: 25
};

const proxy = new Proxy(data, {
  set(target, property, value) {
    if (property === 'age' && typeof value !== 'number') {
      throw new Error('Age must be a number');
    }
    target[property] = value;
    return true;
  }
});

proxy.age = 30; // 合法操作
console.log(proxy.age); // 输出: 30

proxy.age = 'thirty'; // 非法操作,抛出错误
  1. 日志记录和性能监控:
const target = {
  name: 'John',
  age: 25
};

const handler = {
  get(target, property) {
    console.log(`获取属性: ${property}`);
    return target[property];
  },
  set(target, property, value) {
    console.log(`设置属性: ${property}`);
    target[property] = value;
    return true;
  }
};

const proxy = new Proxy(target, handler);

console.log(proxy.name); // 输出: 获取属性: name, John
proxy.age = 30; // 输出: 设置属性: age
  1. 数据绑定和响应式:
const data = {
  name: 'John',
  age: 25
};

const handler = {
  set(target, property, value) {
    target[property] = value;
    console.log(`属性 ${property} 的值变为 ${value}`);
    // 触发界面更新或其他逻辑
    return true;
  }
};

const proxy = new Proxy(data, handler);

proxy.age = 30; // 输出: 属性 age 的值变为 30
  1. 缓存和优化:
function expensiveCalculation() {
  // 执行耗时的计算
  console.log('执行耗时的计算');
  return 100;
}

const handler = {
  get(target, property) {
    if (property === 'result') {
      if (!target.result) {
        target.result = expensiveCalculation();
      }
      return target.result;
    }
    return target[property];
  }
};

const proxy = new Proxy({}, handler);

console.log(proxy.result); // 输出: 执行计算, 100
console.log(proxy.result); // 输出: 100 (缓存的结果)

4. Reflect API 的使用场景

Reflect 对象通常在以下两个场景下使用:

  1. **使用 Proxy 对象:**当你在使用 Proxy 对象时,Reflect 的方法可以使你的代码更简洁、易读,因为 Reflect 的方法与 Proxy handlers 的方法一一对应。
let handler = {
  get(target, key) {
    return Reflect.get(target, key)
  }
}

let p = new Proxy({}, handler)
p.a = 1
console.log(p.a) // 输出:1
  1. **在函数式编程中操作对象:**由于 Reflect 的所有方法都是函数,它可以结合函数式编程中的各种技巧使用,如高阶函数、柯里化等。
let curry = (fn, ...args1) => (...args2) => Reflect.apply(fn, null, [...args1, ...args2])

let push = curry(Array.prototype.push)

let arr = []
push(arr, 1, 2, 3)

console.log(arr)  // 输出:[1, 2, 3]

你可能感兴趣的:(JS高级,javascript,前端)