On gists
Proxy object guide
JavaScript
Proxy.js
Raw
#
// 1) get + set
const target = {
name: 'John Smith',
age: 30,
};
const handler = {
get: function (target, prop) {
console.log(`Getting the property ${prop}`);
return target[prop];
},
set: function (target, prop, value) {
console.log(`Setting the property ${prop} to ${value}`);
target[prop] = value;
},
};
const proxy = new Proxy(target, handler);
// 2) with validator fn aka encapsulation
const withValidators = person => {
const handler = {
set: function (target, prop, value) {
if ((prop === 'age' && value < 0) || value > 120) {
throw new Error('Invalid age');
return;
}
target[prop] = value;
},
};
return new Proxy(person, handler);
};
const person = withValidators({
name: 'John Smith',
age: 30,
});
// 3) caching, proxy wrap only function
const cache = {};
const getWeather = (city) => {
return "fetch -> city -> " + city
};
const proxiedGetWeather = new Proxy(getWeather, {
apply(target, thisArg, args) {
const city = args[0];
if (cache[city]) {
console.log('Loading weather data from cache...');
return cache[city];
}
cache[city] = target.apply(thisArg, args);
return cache[city];
},
});
console.log(proxiedGetWeather('San Francisco'))
console.log(proxiedGetWeather('San Francisco')) // console.log('Loading weather data from cache...');
console.log(proxiedGetWeather('San Francisco')) // console.log('Loading weather data from cache...');
// 4) cannot delete
const handler = {
deleteProperty(target, key) {
if (key.startsWith('_')) {
throw new Error(`Cannot delete internal property '${key}'`);
}
delete target[key];
return true;
},
};
const user = {
name: 'John Smith',
_ssn: 'XXX-YY-ZZZ',
};
const protectedUser = protectInternalProps(user);
// Throw error `Cannot delete internal property '_ssn'`
delete protectedUser._ssn;
// 5 cannot iterate
const handler = {
ownKeys(target) {
return Object.keys(target).filter(key => !key.startsWith('_'));
},
};
const user = {
name: "John Smith",
_ssn: "XXX-YY-ZZZ",
};
const protectedUser = protectInternalProps(user);
console.log(Object.keys(protectedUser)); // ['name']
for (let key in protectedUser) {
console.log(key);
}
// ['name']
// 6) private props in class before exists #privateProps
// https://phuoc.ng/collection/javascript-proxy/implement-private-properties-in-a-javascript-class/
const handler = {
get(target, key) {
if (key.startsWith('_')) {
throw new Error(`Cannot access private property '${key}'`);
}
return target[key];
},
set(target, key, value) {
if (key.startsWith('_')) {
throw new Error(`Cannot modify private property '${key}'`);
}
target[key] = value;
return true;
},
};
class ProtectedPerson {
constructor(name, age, ssn) {
this.name = name;
this.age = age;
this._ssn = ssn;
return new Proxy(this, handler);
}
getSsn() {
return this._ssn;
}
}
// failed
const person = new ProtectedPerson('John Smith', 42, '123-45-6789');
// Uncaught Error: Cannot access private property '_ssn'
person.getSsn();
// lets improve
const handler = {
get(target, key) {
if (key.startsWith('_')) {
throw new Error(`Cannot access private property '${key}'`);
}
const value = target[key];
return typeof value === 'function' ? value.bind(target) : value;
},
};
const person = new ProtectedPerson('John Smith', 42, '123-45-6789');
console.log(person.getSsn()); // 123-45-6789
// 7) exists 'in'
const handler = {
has(target, key) {
console.log(`Checking for ${key} property...`);
return key in target;
},
};
const person = {
name: 'John Smith',
age: 42,
occupation: 'developer',
};
const proxy = new Proxy(person, handler);
// Logs "Checking for name property..." and returns `true`
console.log('name' in proxy);
// Logs "Checking for email property..." and returns `false`
console.log('email' in proxy);
// 9) Reflect API
// AND rest articles and more robust solutions we can found
// https://phuoc.ng/collection/javascript-proxy/