Proxy
let proxy = new Proxy(target, handler)
target: is an object to wrap, can be anything, including functions.handler: proxy configuration, an object with “traps”, methods that intercept operations. – e.g. get trap for reading a property of target, set trap for writing a property into target…
empty handler
- As there are no traps, all operations on
proxyare forwarded totarget.- writing operation
proxy.test=sets the value ontarget - reading operation
proxy.testreturns the value fromtarget for(key in proxy)returns values fromtargettraps
Internal Method Handler Method Triggers when… [[Get]]getreading a property [[Set]]setwriting to a property [[HasProperty]]hasinoperator[[Delete]]deletePropertydeleteoperator[[Call]]applyfunction call [[Construct]]constructnewoperator[[GetPrototypeOf]]getPrototypeOfObject.getPrototypeOf[[SetPrototypeOf]]setPrototypeOfObject.setPrototypeOf[[IsExtensible]]isExtensibleObject.isExtensible[[PreventExtensions]]preventExtensionsObject.preventExtensions[[DefineOwnProperty]]definePropertyObject.defineProperty,Object.defineProperties[[GetOwnProperty]]getOwnPropertyDescriptorObject.getOwnPropertyDescriptor,for..in,Object.keys/values/entries[[OwnPropertyKeys]]ownKeysObject.getOwnPropertyNames,Object.getOwnPropertySymbols,for..in,Object/keys/values/entries
- writing operation
default value with get trap
To intercept reading, the handler should have a method get(target, property, receiver).
target: is thetargetobject, the one passed as the first argument tonew Proxy(target, handler).item: property namereceiver:proxyobject itself.
- We can use
Proxyto implement any logic for “default” values.- non-existing array item returns
0instead ofundefined. - non-existing key-value returns
defaultParseinstead ofundefined. e.g.
- non-existing array item returns
1 | let dictionary = { |
Validation with “set” trap
To intercept setting sth, let’s say we want an array exclusively for numbers. If a value of another type is added, there should be an error.set(target, property, value, receiver)
target: is thetargetobject, the one passed as the first argument tonew Proxy(target, handler).property: property namevalue: property valuereceiver:proxyobject itself, matters only for setter properties.
- The set trap should return
trueif setting is successful, andfalseotherwise (triggers TypeError).
1 | let numbers = []; |
Don’t forget to return
trueThere are
invariants(conditions that must be fulfilled by internal methods and traps) to be held.
e.g.setmust returntrue/falsedeletemust returntrueif the value was deleted successfully…
Built-in func of arrays ins still working
proxydoesn’t break anything.
Iteration with ownKeys and getOwnPropertyDescriptor
ownKeys
Object.keys, for..in loop and most other methods that iterate over object properties use [[OwnPropertyKeys]] (intercepted by ownKeys trap)
Object.getOwnPropertyNames(obj)returns non-symbol keys.Object.getOwnPropertySymbols(obj)returns symbol keys.Object.keys/values()returns non-symbol keys/values withenumerableflag.for..inloops over non-symbol keys withenumerableflag + prototype keys.
- We can use
ownKeystrap to make iteration, likefor...inloop,Object.keys,Object.valueswork differently. - Let’s say skip properties starting with an underscore
_
1 | let user = { |
getOwnPropertyDescriptor
We can use the trap getOwnPropertyDescriptor to intercept calls to [[GetOwnProperty]], and return a descriptor with enumerable: true.
1 | let user = { }; |