Proxy 和 Reflect 是 ES6 引入的强大特性,用于拦截和自定义对象的基本操作。
Proxy 用于创建一个对象的代理,可以拦截并自定义对象的基本操作。
const target = {
name: 'Alice',
age: 25
};
const handler = {
get: function(target, prop) {
console.log(`访问属性: ${prop}`);
return target[prop];
},
set: function(target, prop, value) {
console.log(`设置属性: ${prop} = ${value}`);
target[prop] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 访问属性: name, 输出: Alice
proxy.age = 26; // 设置属性: age = 26
const handler = {
get: function(target, prop, receiver) {
if (prop in target) {
return target[prop];
}
return `属性 ${prop} 不存在`;
}
};
const obj = new Proxy({ name: 'Alice' }, handler);
console.log(obj.name); // 'Alice'
console.log(obj.age); // '属性 age 不存在'
const handler = {
set: function(target, prop, value, receiver) {
if (prop === 'age' && (typeof value !== 'number' || value < 0)) {
throw new Error('Invalid age');
}
target[prop] = value;
return true; // 表示设置成功
}
};
const obj = new Proxy({}, handler);
obj.age = 25; // 成功
obj.age = -1; // Error: Invalid age
const handler = {
has: function(target, prop) {
return prop.startsWith('_') ? false : prop in target;
}
};
const obj = new Proxy({ name: 'Alice', _secret: 'hidden' }, handler);
console.log('name' in obj); // true
console.log('_secret' in obj); // false
const handler = {
deleteProperty: function(target, prop) {
if (prop.startsWith('_')) {
throw new Error('Cannot delete private property');
}
delete target[prop];
return true;
}
};
const obj = new Proxy({ name: 'Alice', _secret: 'hidden' }, handler);
delete obj.name; // 成功
delete obj._secret; // Error
const handler = {
ownKeys: function(target) {
return Object.keys(target).filter(key => !key.startsWith('_'));
}
};
const obj = new Proxy({ name: 'Alice', _secret: 'hidden', age: 25 }, handler);
console.log(Object.keys(obj)); // ['name', 'age']
const handler = {
apply: function(target, thisArg, argumentsList) {
console.log('函数被调用');
return target.apply(thisArg, argumentsList);
}
};
function sum(a, b) {
return a + b;
}
const proxySum = new Proxy(sum, handler);
console.log(proxySum(1, 2)); // 函数被调用, 输出: 3
const handler = {
construct: function(target, argumentsList, newTarget) {
console.log('构造函数被调用');
return new target(...argumentsList);
}
};
function Person(name) {
this.name = name;
}
const ProxyPerson = new Proxy(Person, handler);
const person = new ProxyPerson('Alice'); // 构造函数被调用
Reflect 提供了操作对象的静态方法,与 Proxy 的方法一一对应。
const obj = { name: 'Alice' };
// 使用 Reflect
Reflect.get(obj, 'name'); // 'Alice'
Reflect.set(obj, 'age', 25); // true
Reflect.has(obj, 'name'); // true
Reflect.deleteProperty(obj, 'age'); // true
Reflect.ownKeys(obj); // ['name']
Reflect 通常与 Proxy 一起使用,提供默认行为:
const handler = {
get: function(target, prop, receiver) {
console.log(`获取属性: ${prop}`);
return Reflect.get(target, prop, receiver);
},
set: function(target, prop, value, receiver) {
console.log(`设置属性: ${prop} = ${value}`);
return Reflect.set(target, prop, value, receiver);
}
};
const obj = new Proxy({ name: 'Alice' }, handler);
obj.name; // 获取属性: name
obj.age = 25; // 设置属性: age = 25
function createValidator(target) {
return new Proxy(target, {
set: function(target, prop, value) {
if (prop === 'age' && (typeof value !== 'number' || value < 0)) {
throw new Error('Invalid age');
}
if (prop === 'email' && !value.includes('@')) {
throw new Error('Invalid email');
}
return Reflect.set(target, prop, value);
}
});
}
const user = createValidator({});
user.age = 25; // 成功
user.age = -1; // Error
user.email = 'test'; // Error
user.email = '[email protected]'; // 成功
function createLogger(target) {
return new Proxy(target, {
get: function(target, prop) {
console.log(`读取: ${prop}`);
return Reflect.get(target, prop);
},
set: function(target, prop, value) {
console.log(`写入: ${prop} = ${value}`);
return Reflect.set(target, prop, value);
}
});
}
const obj = createLogger({ name: 'Alice' });
obj.name; // 读取: name
obj.age = 25; // 写入: age = 25
function createDefaultObject(defaultValue) {
return new Proxy({}, {
get: function(target, prop) {
return prop in target ? target[prop] : defaultValue;
}
});
}
const obj = createDefaultObject(0);
console.log(obj.count); // 0
obj.count = 5;
console.log(obj.count); // 5
console.log(obj.unknown); // 0
function createNegativeArray(array) {
return new Proxy(array, {
get: function(target, prop, receiver) {
const index = Number(prop);
if (index < 0) {
return target[target.length + index];
}
return Reflect.get(target, prop, receiver);
}
});
}
const arr = createNegativeArray([1, 2, 3, 4, 5]);
console.log(arr[-1]); // 5
console.log(arr[-2]); // 4
function createValidatedFunction(fn, validator) {
return new Proxy(fn, {
apply: function(target, thisArg, argumentsList) {
if (validator) {
validator(argumentsList);
}
return Reflect.apply(target, thisArg, argumentsList);
}
});
}
function sum(a, b) {
return a + b;
}
const validatedSum = createValidatedFunction(sum, (args) => {
if (args.length !== 2) {
throw new Error('需要两个参数');
}
if (typeof args[0] !== 'number' || typeof args[1] !== 'number') {
throw new Error('参数必须是数字');
}
});
console.log(validatedSum(1, 2)); // 3
validatedSum(1); // Error
validatedSum('1', 2); // Error
function reactive(target) {
const handlers = [];
const proxy = new Proxy(target, {
set: function(target, prop, value) {
const oldValue = target[prop];
const result = Reflect.set(target, prop, value);
if (oldValue !== value) {
handlers.forEach(handler => handler(prop, value, oldValue));
}
return result;
}
});
proxy.onChange = function(handler) {
handlers.push(handler);
};
return proxy;
}
const data = reactive({ count: 0 });
data.onChange((prop, newVal, oldVal) => {
console.log(`${prop} changed from ${oldVal} to ${newVal}`);
});
data.count = 1; // count changed from 0 to 1
data.count = 5; // count changed from 1 to 5
Reflect 方法返回布尔值表示操作是否成功:
const obj = { name: 'Alice' };
// 成功时返回 true
Reflect.set(obj, 'age', 25); // true
Reflect.deleteProperty(obj, 'age'); // true
// 失败时返回 false(不会抛出错误)
const frozen = Object.freeze({ name: 'Alice' });
Reflect.set(frozen, 'name', 'Bob'); // false
Reflect.deleteProperty(frozen, 'name'); // false