-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathdummy_membrane.js
56 lines (50 loc) · 1.84 KB
/
dummy_membrane.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* @deprecated: see membrane.js for a more complete implementation of membranes.
*
* A simple membrane that doesn't distinguish between "inward"
* and "outward" crossing of the membrane.
*
* Uses a "dummy target" to enable Object.getPrototypeOf to expose
* a wrapped prototype. Exposing non-configurable own properties of
* the real target will still fail. Why? See:
* http://soft.vub.ac.be/~tvcutsem/invokedynamic/frozen-proxies
*
* @author tvcutsem
*
* For a general introduction to membranes, see:
* http://soft.vub.ac.be/~tvcutsem/invokedynamic/js-membranes
*
* usage:
* var membrane = makeMembrane(obj)
* var wrappedObj = membrane.target;
* var wrappedX = wrappedObj.x; // accessed objects are recursively wrapped
* membrane.revoke(); // touching any wrapped value after this point throws
*/
function makeMembrane(initTarget) {
var cache = new WeakMap();
var revoked = false;
function wrap(target) {
if (Object(target) !== target) return target; // primitives are passed through
var wrapper = cache.get(target);
if (wrapper) return wrapper;
var dummyTarget;
if (typeof target === "function") {
dummyTarget = target;
} else {
dummyTarget = Object.create(wrap(Object.getPrototypeOf(target)));
}
wrapper = Proxy(dummyTarget, Proxy(dummyTarget, { // "double lifting"
get: function(dummyTarget, trapName) {
if (revoked) throw new TypeError("membrane revoked");
return function(dummyTarget /*, ...args*/) { // generic trap
var args = Array.prototype.slice.call(arguments, 1).map(wrap);
return wrap(Reflect[trapName].apply(undefined, [target].concat(args)));
}
}
}));
cache.set(target, wrapper);
return wrapper;
}
function revoke() { revoked = true; }
return {revoke: revoke, target: wrap(initTarget)};
}