Proxy 原理解析与应用

38 阅读2分钟

一、Proxy 核心原理

1.1 基础概念

Proxy 是 ES6 引入的元编程特性,通过创建代理对象拦截目标对象(target)的操作。其工作机制可概括为:

	const proxy = new Proxy(target, handler);
  • 目标对象(target) :被代理的原始对象
  • 处理器对象(handler) :定义拦截行为的配置对象,包含 13 种捕获器(traps)

1.2 内部方法映射

Proxy 通过内部方法实现操作拦截,常见映射关系如下:

内部方法对应捕获器触发场景
[[Get]]get属性读取 obj.prop
[[Set]]set属性赋值 obj.prop = v
[[Apply]]apply函数调用 fn(...args)
[[HasProperty]]hasin 操作符 prop in obj

1.3 执行流程示例

	const target = { name: "Alice" };

	const handler = {

	  get(target, prop) {

	    console.log(`Reading ${prop}`);

	    return target[prop];

	  }

	};

	const proxy = new Proxy(target, handler);

	proxy.name; // 输出:Reading name → "Alice"

二、核心捕获器详解

2.1 get 捕获器(属性读取)

应用场景:依赖收集、懒加载

	// Vue 3 响应式简化版

	function reactive(target) {

	  return new Proxy(target, {

	    get(target, prop, receiver) {

	      trackDependency(prop); // 收集依赖

	      return Reflect.get(target, prop, receiver);

	    }

	  });

	}

2.2 set 捕获器(属性设置)

应用场景:数据验证、自动更新

	const user = new Proxy({}, {

	  set(target, prop, value) {

	    if (prop === 'age' && typeof value !== 'number') {

	      throw new Error('年龄必须为数字');

	    }

	    triggerUpdate(prop); // 触发更新

	    target[prop] = value;

	    return true;

	  }

	});

2.3 apply 捕获器(函数调用)

应用场景:防抖/节流封装

	// 防抖函数封装

	function debounce(fn, delay = 300) {

	  let timer;

	  return new Proxy(fn, {

	    apply(target, ctx, args) {

	      clearTimeout(timer);

	      timer = setTimeout(() => Reflect.apply(target, ctx, args), delay);

	    }

	  });

	}

三、典型应用场景

3.1 响应式系统实现

Vue 3 对比 Vue 2

	// Vue 2(Object.defineProperty 缺陷)

	Object.defineProperty(obj, 'prop', {

	  get() { /* 无法监听新增属性 */ },

	  set() { /* 需手动处理数组变化 */ }

	})

	 

	// Vue 3(Proxy 优势)

	const state = reactive({ count: 0 });

	effect(() => {

	  console.log(state.count); // 自动收集依赖

	});

3.2 数据权限控制

	const secureObj = new Proxy({ secret: '123' }, {

	  get(target, prop) {

	    if (prop === 'secret' && !isAdmin) {

	      throw new Error('无权限访问');

	    }

	    return target[prop];

	  }

	});

3.3 函数式编程优化

	// 不可变数据结构

	const immutableData = new Proxy(originalData, {

	  set() {

	    throw new Error('数据不可修改');

	  }

	});

四、性能与兼容性

4.1 性能优势

  • 批量操作优化:Proxy 的 set 捕获器可合并多次更新:

    	const optimizedObj = new Proxy({}, {
    
    	  set(target, prop, value) {
    
    	    requestAnimationFrame(() => {
    
    	      target[prop] = value;
    
    	      render();
    
    	    });
    
    	    return true;
    
    	  }
    
    	});
    

4.2 兼容性考虑

  • 浏览器支持:Chrome 49+/Firefox 18+/Safari 10+

  • 降级方案

    	const fallback = obj => 
    
    	  Proxy ? new Proxy(obj, handler) : obj;
    

五、进阶实践案例

5.1 深度监听实现

	const deepReactive = (target) => {

	  return new Proxy(target, {

	    get(target, prop) {

	      const value = target[prop];

	      return typeof value === 'object' ? deepReactive(value) : value;

	    },

	    set(target, prop, value) {

	      target[prop] = value;

	      triggerDeepUpdate(prop);

	      return true;

	    }

	  });

	};

5.2 接口调用封装

	const apiProxy = new Proxy(() => {}, {

	  apply(target, ctx, [url, config]) {

	    return fetch(url, config)

	      .then(res => res.json())

	      .catch(handleError);

	  }

	});

六、总结

Proxy 通过强大的拦截机制重新定义了 JavaScript 对象操作方式,其核心价值体现在:

  1. 统一操作拦截:替代 Vue 2 的递归属性监听
  2. 动态行为扩展:如防抖函数、权限控制
  3. 性能优化空间:批量更新、懒加载
  4. 代码简洁性:减少 70%+ 的响应式代码