Proxy - object wraps another object and intercepts operations, like reading/writing properties Proxy provide a way to tweak the behavior of the existing objects at the lowest level Proxy is more powerful than just a fn wrapper, as it forwards everything to the target object Syntax let proxy = new Proxy(target, handler) target - object to wrap, can be anything, including functions handler – proxy configuration: an object with “traps”, methods that intercept operations Handler methods Triggers when get - reading a property set - writing to a property has - in operator deleteProperty - delete operator apply - function call construct - new operator getPrototypeOf - Object.getPrototypeOf setPrototypeOf - Object.setPrototypeOf isExtensible - Object.isExtensible preventExtensions - Object.preventExtensions defineProperty - Object.defineProperty , Object.defineProperties getOwnPropertyDescriptor - Object.getOwnPropertyDescriptor , for...in , Object.keys/values/entries ownKeys - Object.getOwnPropertyNames , Object.getOwnPropertySymbols , for...in , Object.keys/values/entries No own properties With an empty handler it transparently forwards operations to target let target = {} let proxy = new Proxy(target, {}) // empty handler proxy.test = 5 target.test // 5 proxy.test // 5 for(let key in proxy) alert(key); // test Get trap Get trap triggers when a property is read let numbers = [0, 1, 2] numbers = new Proxy(numbers, { get(target, prop) { if (prop in target) return target[prop] return 0 } }) numbers[1] // 1 numbers[123] // 0 (no such item) let dictionary = { 'Hello': 'Hola', 'Bye': 'Adiós' } dictionary = new Proxy(dictionary, { get(target, phrase) { if (phrase in target) return target[phrase] return "no translation" } } ) dictionary['Hello'] // Hola dictionary['Welcome to Proxy'] // no translation Set trap Set trap triggers when a property is written let numbers = [] numbers = new Proxy(numbers, { set(target, prop, val) { // to intercept property writing if (typeof val !== 'number') return false target[prop] = val; return true } }) numbers.push(1) // added successfully numbers.push(2) // added successfully numbers.push("test") // TypeError ('set' on proxy returned false) numbers // Proxy {0: 1, 1: 2} ownKeys Skip props with keys starting from "_" let user = { name: "John", age: 30, _password: "***" } user = new Proxy(user, { ownKeys(target) { return Object.keys(target).filter(key => !key.startsWith('_')); } }) for(let key in user) alert(key); // name, age Object.keys(user) // ['name', 'age'] Object.values(user) // ['John', 30] apply Make a wrapper function, which delays original function by 3s function delay(f, ms) { return new Proxy(f, { apply(target, thisArg, args) { setTimeout(() => target.apply(thisArg, args), ms) } }) } function sayHi(user) { alert(`Hello, ${user}!`) } sayHi = delay(sayHi, 3000) sayHi.length // 1 // proxy forwards "get length" operation to the target sayHi("John"); // Hello, John! (after 3 seconds)