Skip to content

Latest commit

 

History

History
186 lines (179 loc) · 6.65 KB

traps.md

File metadata and controls

186 lines (179 loc) · 6.65 KB

Proxy Traps

The following table shows Javascript code on the left, and approximately how that code is trapped and interpreted by the Proxy mechanism on the right.

Assume proxy is defined as:

var proxy = new Proxy(target, handler)

See further notes below for details.

Syntactic operations that can be intercepted
Operation Code Trapped as
property access proxy.foo
proxy['foo']
handler.get(target, 'foo', proxy)
property assignment proxy.foo = v
proxy['foo'] = v
handler.set(target, 'foo', v, proxy)
property invocation (1) proxy.foo(1,2,3) handler.get(target, 'foo', proxy).apply(proxy, [1,2,3])
property query 'foo' in proxy handler.has(target, 'foo')
property deletion delete proxy.foo
delete proxy['foo']
handler.deleteProperty(target, 'foo')
property enumeration for (var prop in proxy) { ... }
var $iterator = handler.enumerate(target);
var $nxt = iterator.next();
while (!$nxt.done) {
  var prop = String($nxt.value);
  ...
  $nxt = $iterator.next();
}
inherited property access var obj = Object.create(proxy);
obj.foo;
handler.get(target, 'foo', obj)
inherited property assignment var obj = Object.create(proxy);
obj.foo = v;
handler.set(target, 'foo', v, obj)
Operations on function proxies
function call (3) proxy(...args) handler.apply(target, undefined, args)
function construct new proxy(...args) handler.construct(target, args, proxy)
method call (4) object.proxy(...args) handler.apply(target, object, args)
Function.prototype.call (5) proxy.call(object, ...args) handler.apply(target, object, args)
Non-interceptable operators
typeof test typeof proxy (typeof target === "function") ? "function" : "object"
identity comparison proxy === v proxy === v
Built-ins inherited from Object.prototype
hasOwnProperty (6) proxy.hasOwnProperty('foo') handler.hasOwn(target, 'foo')
valueOf (7) proxy.valueOf() target.valueOf()
toString (8) proxy.toString() target.toString()
(Static) operations on Object
getOwnPropertyNames Object.getOwnPropertyNames(proxy) handler.ownKeys(target)
getOwnPropertyDescriptor (9) Object.getOwnPropertyDescriptor(proxy, 'foo') handler.getOwnPropertyDescriptor(target, 'foo')
defineProperty (10) Object.defineProperty(proxy, 'foo', {value:42}) handler.defineProperty(target, 'foo', {value:42,writable:true,enumerable:true,configurable:true})
defineProperties (10) Object.defineProperties(proxy, {foo: {value:42}}) handler.defineProperty(target, 'foo', {value:42,writable:true,enumerable:true,configurable:true})
preventExtensions Object.preventExtensions(proxy) handler.preventExtensions(target)
isExtensible Object.isExtensible(proxy) handler.isExtensible(target)
getPrototypeOf Object.getPrototypeOf(proxy) handler.getPrototypeOf(target)
setPrototypeOf (11) Object.setPrototypeOf(proxy, newProto) handler.setPrototypeOf(target, newProto)
keys (12) Object.keys(proxy) handler.ownKeys(target)

Notes

  • (1): in Javascript, a method call like obj.foo(1,2,3) is defined as looking up the "foo" property on obj, and then calling the resulting function with obj as the this-binding. If obj is a proxy, the same strategy applies. There is no separate invoke trap.
  • (3): the syntax ...args is ECMAScript 6 syntax for "spreading" arguments into a call. f(...[1,2,3]) is equivalent to f(1,2,3). Function calls can only be intercepted if the target is a function, i.e. typeof target === "function".
  • (4): this assumes that the proxy was installed as a method on object, e.g. var object = { proxy: new Proxy(target, handler) }.
  • (5): assuming that proxy.call, which triggers the proxy's "get" trap, returned Function.prototype.call.
  • (6): assuming that proxy.hasOwnProperty, which triggers the proxy's "get" trap, returned Object.prototype.hasOwnProperty.
  • (7): assuming that proxy.valueOf, which triggers the proxy's "get" trap, returned Object.prototype.valueOf.
  • (8): assuming that proxy.toString, which triggers the proxy's "get" trap, returned Object.prototype.toString.
  • (9): the return value of the getOwnPropertyDescriptor trap (the property descriptor object) is not the original value returned from the intercepted Object.getOwnPropertyDescriptor call. Rather, it is a fresh descriptor object that is guaranteed to be "complete" (i.e. to define values for all relevant ECMAScript property attributes).
  • (10): the third argument to the defineProperty trap (the property descriptor object) is not the original value passed into the intercepted Object.defineProperty call. Rather, it is a fresh descriptor object that is guaranteed to be "complete" (i.e. to define values for all relevant ECMAScript property attributes). For Object.defineProperties(proxy,props), the proxy's defineProperty trap is called for each own enumerable property of props.
  • (11): only on platforms that support mutable __proto__ and where __proto__ is an accessor property defined on Object.prototype.
  • (12): the ownKeys trap must return all own property names. Object.keys then retains only the keys denoting enumerable properties.