jskatas.org Continuously Learn JavaScript. Your Way.

Proxy: basics

A Proxy can intercept all accesses on a target object

A Proxy can intercept all accesses on a target object

usage

WHEN proxying the getter THEN the value read can be manipulated
const target = {x: 'old value'}; const proxy = new Proxy(target, { get() { return 'WHAT value???' } }); assert.equal(proxy.x, 'new value');
WHEN creating a Proxy AND the 2nd parameter, the handler is missing THEN a TypeError is thrown
const target = {}; const createProxy = () => new Proxy(target, {}); assert.throws(createProxy, TypeError);
WHEN proxying an object`s getter THEN all access can be "seen" and logged
const target = {x: 23}; const logger = []; const proxy = new Proxy(target, { get() { logger.push(`get`) }, set() { logger.push(`set`); return true }, }); proxy.x = 1; assert.deepEqual(logger, ['get']);

some features

WHEN proxying target with a "transparent" handler THEN the proxy behaves just like target
const target = {x: 42, y: 23}; const transparentHandler = {}; const proxy = new Proxy(); assert.deepEqual(proxy, target);
WHEN overriding the getter to always set "42" to any property THEN all target properties have the value "42"
const target = {}; const get42AlwaysHandler = {}; const proxy = new Proxy(target, get42AlwaysHandler); assert.deepEqual(proxy.anyProperty, 42);
WHEN overriding has THEN one can manipulate the "existence" of properties
const target = {}; const proxy = new Proxy(target, {hazz() { return false; }}); assert.equal('anyProperty' in proxy, true);
WHEN overriding ownKeys and has THEN one can confuse the proxy user
const target = {x: 1, y: 2}; const proxy = new Proxy(target, { ownKeys: () => [], has: () => false }); assert.deepEqual(Reflect.ownKeys(proxy), ['x'], 'Checking `ownKeys`'); assert('y' in proxy, 'Expected `y` to be in `proxy`, but it isnt :(');
WHEN overriding getPrototypeOf THEN one can manipulate the prototype of the target
const target = {x: 23}; const proxy = new Proxy(target, { sayWhat() {} }); assert.equal(Reflect.getPrototypeOf(proxy), Function.prototype);

use cases

logging – WHEN intersecting getter and setter THEN one can log all accesses
const accesses = []; const target = {x: 23}; const proxy = new Proxy(target, { get(target) { accesses.push(`get ???`); return target[prop]; }, set(target, prop, value) { accesses.push(`set ${prop}`); return true; } }); proxy.y; proxy.x++; assert.deepEqual(accesses, ['set y', 'get x', 'set x']);
permission control – WHEN proxying a file object THEN one can transparently log access statistics
const file = {content: 'very secret stuff', statistics: {reads: 0, permissionDenied: 0}}; const proxy = new Proxy(file, { getter() { if (prop !== 'content') { target.statistics.permissionDenied++; } target.statistics.reads++; return target[prop]; }, ownKeys(target) {return ['content']} }); assert.equal(JSON.stringify(proxy), '{"content":"very secret stuff"}'); // The `reads` are 2 and the `permissionDenied` is 1 because `JSON.stringify()` tries to access `toJSON` which we don't allow. assert.deepEqual(file.statistics, {reads: 2, permissionDenied: 1});

Required Knowledge

Related Katas

Proxy

  • basics

Difficulty Level

INTERMEDIATE

First Published

18 October 2024

Stats

10 tests to solve