Permalink
Browse files

added preliminary support for revocable proxies

  • Loading branch information...
tvcutsem committed Sep 24, 2012
1 parent 85b55ed commit 48f455e3a1042863c9cf675fac799b3281143b71
Showing with 46 additions and 2 deletions.
  1. +16 −1 doc/api.md
  2. +1 −1 doc/handler_api.md
  3. +18 −0 reflect.js
  4. +11 −0 test/testProxies.js
View
@@ -212,4 +212,19 @@ The following `Handler` traps are regarded as "fundamental", and by default forw
All other traps are "derived", and default to one or more of the above "fundamental" traps: get, set, has, hasOwn, keys, enumerate, iterate, seal, freeze, isSealed, isFrozen, construct.
-[More details](http://wiki.ecmascript.org/doku.php?id=harmony:virtual_object_api)
+[More details](http://wiki.ecmascript.org/doku.php?id=harmony:virtual_object_api)
+
+## Proxy.revocable(target, handler)
+
+Returns an object with properties `proxy` and `revoke`. `proxy` is a freshly constructed proxy, as if by calling `Proxy(target, handler)`. `revoke()` is a function that when called, renders the associated proxy unusable: any trappable operation performed on `proxy` after it has been revoked results in a TypeError.
+
+When a proxy is revoked, it no longer refers to its `target` and `handler` so that these may become subject to garbage-collection.
+
+Example:
+
+ var tuple = Proxy.revocable(target, handler);
+ var proxy = tuple.proxy;
+ var revoke = tuple.revoke;
+ proxy.foo // traps
+ revoke() // returns undefined
+ proxy.foo // throws TypeError: "proxy is revoked"
View
@@ -121,7 +121,7 @@ The proxy throws a TypeError if:
* This trap returns `undefined`, but the `name` property of `target` is non-configurable. If a target property is non-configurable, a proxy cannot hide it.
* This trap returns a property descriptor that is not compatible with the corresponding property in `target` (e.g. `target[name]` is non-configurable and this trap returns a configurable descriptor).
- * This trap returns a non-configurable property that doesn't exist on `target`. A non-configurable property can only be exposed if the `target` object has a corresponding property.
+ * This trap returns a non-configurable property that is configurable or doesn't exist on `target`. A non-configurable property can only be exposed if the `target` object has a corresponding non-configurable property.
Examples:
View
@@ -1030,6 +1030,8 @@ Validator.prototype = {
* - create and return a fresh Array,
* - of which each element is coerced to String,
* - which does not contain duplicates
+ *
+ * TODO(tvcutsem) trap return value should change from [string] to iterator.
*/
enumerate: function() {
var trap = this.getTrap("enumerate");
@@ -1966,6 +1968,22 @@ if (typeof Proxy !== "undefined") {
directProxies.set(proxy, vHandler);
return proxy;
};
+
+ Reflect.Proxy.revocable = function(target, handler) {
+ var proxy = Reflect.Proxy(target, handler);
+ var revoke = function() {
+ var vHandler = directProxies.get(proxy);
+ if (vHandler !== null) {
+ // vHandler.target = null; // null-out [[Target]]
+ Object.defineProperty(vHandler, 'target', {
+ get: function() { throw new TypeError("proxy is revoked"); }
+ });
+ }
+ directProxies.set(proxy, null); // null-out [[Handler]]
+ return undefined;
+ };
+ return {proxy: proxy, revoke: revoke};
+ }
} else {
// Proxy is already a function, so presumably direct proxies
View
@@ -95,6 +95,7 @@ load('../reflect.js');
testFunctions();
testSet();
testTransparentWrappers();
+ testRevocableProxies();
for (var testName in TESTS) {
emulatedProps = {};
@@ -731,6 +732,16 @@ load('../reflect.js');
'Array.prototype.toString on app');
}());
}
+
+ function testRevocableProxies() {
+ var target = {};
+ var handler = { get: function() { return 1; }};
+ var tuple = Proxy.revocable(target, handler);
+ var p = tuple.proxy;
+ assert(p.x === 1, 'unrevoked proxy get works');
+ tuple.revoke();
+ assertThrows('proxy is revoked', function() { p.x });
+ }
if (typeof window === "undefined") {
test();

0 comments on commit 48f455e

Please sign in to comment.