javascript中实现代理的核心机制是es6的proxy对象,它通过拦截目标对象的操作实现自定义行为,需传入目标对象和包含get、set、apply等陷阱方法的handler对象,结合reflect确保正确执行默认操作,从而实现如数据校验、响应式系统等高级功能,相比object.defineproperty具有拦截更全面、支持动态属性和数组操作的优势,尽管存在兼容性限制,但已成为现代前端框架如vue 3实现响应式系统的首选方案。

JavaScript中实现代理的核心机制,无疑就是ES6引入的
Proxy
new
Proxy
要使用
Proxy
target
handler
handler
get
set
apply
一个最基础的代理实现看起来是这样的:
const targetObject = {
message: 'Hello, world!',
count: 0
};
const handler = {
// 拦截属性读取
get(target, property, receiver) {
console.log(`有人尝试读取属性: ${String(property)}`);
// 使用Reflect.get确保默认行为,并正确处理this指向
return Reflect.get(target, property, receiver);
},
// 拦截属性设置
set(target, property, value, receiver) {
console.log(`有人尝试设置属性: ${String(property)} 为 ${value}`);
if (property === 'count' && typeof value !== 'number') {
console.warn('count属性必须是数字!');
return false; // 阻止设置
}
// 使用Reflect.set确保默认行为
return Reflect.set(target, property, value, receiver);
}
};
const proxiedObject = new Proxy(targetObject, handler);
// 测试代理
console.log(proxiedObject.message); // 触发get拦截
proxiedObject.count = 10; // 触发set拦截
proxiedObject.count = 'abc'; // 触发set拦截,并被警告
console.log(proxiedObject.count);在这里,
Reflect
Proxy
Reflect
this
Proxy
Reflect
Proxy
Proxy
get(target, property, receiver)
receiver
set(target, property, value, receiver)
set
apply(target, thisArg, argumentsList)
apply
construct(target, argumentsList, newTarget)
new
construct
除了这些,还有一些不那么常用但同样强大的拦截器,比如:
has(target, property)
in
deleteProperty(target, property)
delete
defineProperty(target, property, descriptor)
Object.defineProperty
getOwnPropertyDescriptor(target, property)
Object.getOwnPropertyDescriptor
getPrototypeOf(target)
Object.getPrototypeOf
isExtensible(target)
Object.isExtensible
ownKeys(target)
Object.keys()
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
每种拦截器都对应着JavaScript对象操作的某个环节,提供了极大的灵活性去定制对象的行为。
在前端框架中,尤其是涉及到数据响应式时,我们常常会把
Proxy
Object.defineProperty
Proxy
Proxy
Object.defineProperty
Proxy
get
set
deleteProperty
apply
construct
in
has
ownKeys
Proxy
Object.defineProperty
Object.defineProperty
Proxy
Object.defineProperty
push
pop
shift
Proxy
set
deleteProperty
Proxy
Proxy
Proxy
Object.defineProperty
this
Proxy
this
handler
Reflect
this
Proxy
Proxy
总的来说,
Proxy
Object.defineProperty
Proxy
Object.defineProperty
Proxy
利用
Proxy
这里我们构建一个非常简化的模型,不考虑嵌套对象、数组方法等复杂情况,只关注核心的
get
set
// 存储当前正在执行的“副作用”函数(effect function)
let activeEffect = null;
// 用于收集依赖的Map
// key: target对象
// value: Map (key: property, value: Set of effects)
const targetMap = new WeakMap();
// 依赖收集函数
function track(target, key) {
if (activeEffect) { // 只有在有副作用函数正在执行时才收集
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect); // 将当前副作用函数添加到依赖集合中
}
}
// 依赖触发函数
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return; // 如果没有依赖,直接返回
const dep = depsMap.get(key);
if (dep) {
dep.forEach(effect => effect()); // 遍历并执行所有依赖该属性的副作用函数
}
}
// 包装副作用函数
function effect(fn) {
const effectFn = () => {
activeEffect = effectFn; // 设置当前正在执行的副作用函数
try {
fn(); // 执行副作用函数,期间会触发get拦截,进行依赖收集
} finally {
activeEffect = null; // 执行完毕后清空
}
};
effectFn(); // 立即执行一次,进行初始的依赖收集
return effectFn; // 返回effect函数,方便后续手动停止或执行
}
// 响应式化函数
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key); // 收集依赖
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
trigger(target, key); // 触发依赖
return result;
}
});
}
// --- 使用示例 ---
const state = reactive({
count: 0,
name: 'World'
});
console.log('--- 第一次 effect ---');
effect(() => {
console.log(`Count is: ${state.count}`); // 读取state.count,进行依赖收集
});
console.log('--- 第二次 effect ---');
effect(() => {
console.log(`Hello, ${state.name}!`); // 读取state.name,进行依赖收集
});
console.log('\n--- 改变 count ---');
state.count++; // 触发set,然后触发effect函数重新执行
console.log('count changed to', state.count);
console.log('\n--- 改变 name ---');
state.name = 'Vue'; // 触发set,然后触发effect函数重新执行
console.log('name changed to', state.name);
console.log('\n--- 再次改变 count ---');
state.count += 5;这个例子展示了
Proxy
get
effect
set
activeEffect
effect
以上就是JS如何实现代理?Proxy的拦截器的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号