JavaScript Proxy 知识点笔记

24 阅读2分钟

Proxy 是 ECMAScript 2015(ES6)中引入的一个新特性,它允许你创建一个对象的代理来定义其基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等等)。Proxy 对象可以拦截并自定义这些操作的行为。

1. Proxy 的基本语法

let proxy = new Proxy(target, handler);
  • target:要用 Proxy 包装的目标对象。
  • handler:一个对象,其属性是当执行一个操作时定义代理行为的方法。

2. handler 对象的方法

  • get(target, propKey, receiver):拦截读取属性操作。
  • set(target, propKey, value, receiver):拦截写入属性操作。
  • has(target, propKey):拦截 in 操作符。
  • deleteProperty(target, propKey):拦截 delete 操作符。
  • apply(target, thisArg, argumentsList):拦截函数调用。
  • construct(target, argumentsList, newTarget):拦截 new 操作符。
  • ownKeys(target) ‌*:拦截 Object.keysObject.getOwnPropertyNamesObject.getOwnPropertySymbols
  • defineProperty(target, propKey, attributes):拦截 Object.definePropertyObject.defineProperties
  • getOwnPropertyDescriptor(target, propKey):拦截 Object.getOwnPropertyDescriptor
  • setPrototypeOf(target, prototype):拦截 Object.setPrototypeOf
  • getPrototypeOf(target):拦截 Object.getPrototypeOf
  • isExtensible(target):拦截 Object.isExtensible
  • preventExtensions(target):拦截 Object.preventExtensions

3. 使用示例

let target = {
  message1: 'hello',
  message2: 'everyone'
};

let handler = {
  get: function(target, prop, receiver) {
    if (prop === 'message1') {
      return 'Hello, Proxy!';
    }
    return Reflect.get(...arguments);
  }
};

let proxy = new Proxy(target, handler);

console.log(proxy.message1); // "Hello, Proxy!"
console.log(proxy.message2); // "everyone"

4. 在 Vue2 + Element-UI 项目中的实际使用

在 Vue2 + Element-UI 项目中,Proxy 可以用于各种高级场景,比如数据劫持、表单验证、API 请求的封装等。下面是一个简单的示例,展示如何在 Vue 组件中使用 Proxy 来封装 axios 请求,并在组件的生命周期中自动处理请求和响应。

<template>
  <div>
    <el-button type="primary" @click="fetchData">Fetch Data</el-button>
    <div v-if="data">
      <!-- 渲染数据 -->
      {{ data }}
    </div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      data: null,
      api: null,
    };
  },
  created() {
    // 创建一个 Proxy 来封装 axios 请求
    this.api = new Proxy({}, {
      get: (target, prop, receiver) => {
        return (...args) => {
          return axios[prop](...args)
            .then(response => {
              // 可以在这里统一处理响应数据,比如错误处理、数据格式化等
              return response.data;
            })
            .catch(error => {
              // 统一错误处理
              this.$message.error('Request failed: ' + error.message);
              throw error;
            });
        };
      }
    });
  },
  methods: {
    fetchData() {
      // 使用 Proxy 封装的 axios 请求方法
      this.api.get('/api/data')
        .then(data => {
          this.data = data;
        })
        .catch(error => {
          // 错误已经在 Proxy 中处理,这里不需要再次处理
          console.error(error);
        });
    }
  }
};
</script>

<style scoped>
/* 添加样式 */
</style>

在这个示例中,创建了一个 Proxy 对象 api,它拦截了对 axios 方法的调用。在 get 陷阱中,根据传入的属性名(比如 'get''post' 等)动态地返回一个新的函数,这个函数会调用对应的 axios 方法,并处理响应和错误。这样,我们就可以在组件中通过 this.api.getthis.api.post 等方式发起请求,而不需要每次都写完整的 axios 调用代码,同时还可以在 Proxy 中统一处理错误和响应数据。