mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-22 05:59:31 +08:00
- Keep cached native class instances callable, including inherited methods and JavaScript arguments. - Support plain-object Proxy traps with live receivers, enumeration, and data-property invariants. - Compile untyped addition, computed environment keys, and text-codec startup storage natively.
110 lines
5.6 KiB
JavaScript
110 lines
5.6 KiB
JavaScript
const values = { one: 1, two: 2 };
|
|
function erase(object, key) { delete object[key]; }
|
|
let trace = "";
|
|
const proxy = new Proxy({}, {
|
|
get(target, key, receiver) {
|
|
trace += `get:${key};`;
|
|
if (key === "identity") return receiver;
|
|
if (key === "method") return function(value) { return this.one + value; };
|
|
return values[key];
|
|
},
|
|
has(target, key) { trace += `has:${key};`; return key in values; },
|
|
ownKeys() { trace += "keys;"; return ["two", "hidden", "one", "absent"]; },
|
|
getOwnPropertyDescriptor(target, key) {
|
|
trace += `desc:${key};`;
|
|
if (key === "absent") return;
|
|
return { configurable: true, enumerable: key !== "hidden", get: () => values[key] };
|
|
}
|
|
});
|
|
console.log(proxy.one, proxy.identity === proxy, proxy.method(4));
|
|
console.log(typeof proxy, !!proxy, Array.isArray(proxy), proxy !== new Proxy({}, {}));
|
|
console.log("one" in proxy, "no" in proxy, trace);
|
|
trace = "";
|
|
console.log(Object.keys(proxy).join(","), trace);
|
|
trace = "";
|
|
console.log(Object.values(proxy).join(","), trace);
|
|
trace = "";
|
|
console.log(Object.entries(proxy).join("|"), trace);
|
|
trace = "";
|
|
console.log(Object.hasOwn(proxy, "one"), Object.hasOwn(proxy, "absent"), trace);
|
|
const descriptor = Object.getOwnPropertyDescriptor(proxy, "one");
|
|
console.log(descriptor.enumerable, descriptor.configurable, descriptor.set === undefined, descriptor.get());
|
|
values.one = 8;
|
|
console.log(proxy.one, descriptor.get());
|
|
function readGlobalProxy() { return proxy.one; }
|
|
console.log(readGlobalProxy());
|
|
const target = { count: 1 };
|
|
const handler = { get: function(obj, key, receiver) { return obj[key] + (this === handler ? 10 : 0); } };
|
|
const live = new Proxy(target, handler);
|
|
console.log(live.count);
|
|
target.count = 3;
|
|
handler.get = function(obj, key) { return obj[key] + 20; };
|
|
console.log(live.count);
|
|
erase(handler, "get");
|
|
console.log(live.count, Object.keys(live).join(","));
|
|
const mutator = new Proxy(target, {
|
|
set(obj, key, value, receiver) { obj[key] = value; return true; },
|
|
deleteProperty(obj, key) { delete obj[key]; return true; }
|
|
});
|
|
mutator.count = 7;
|
|
console.log(target.count);
|
|
erase(mutator, "count");
|
|
console.log(Object.keys(target).length);
|
|
function membership(value, key) { return key in value; }
|
|
const throws = new Proxy({}, {
|
|
get() { throw new Error("get failed"); },
|
|
has() { throw new Error("has failed"); },
|
|
ownKeys() { throw new Error("keys failed"); },
|
|
getOwnPropertyDescriptor() { throw new Error("descriptor failed"); }
|
|
});
|
|
try { console.log(throws.x); } catch (error) { console.log(error.message); }
|
|
try { console.log("x" in throws); } catch (error) { console.log(error.message); }
|
|
try { console.log(membership(throws, "x")); } catch (error) { console.log(error.message); }
|
|
try { console.log(Object.keys(throws)); } catch (error) { console.log(error.message); }
|
|
try { console.log(Object.hasOwn(throws, "x")); } catch (error) { console.log(error.message); }
|
|
const duplicates = new Proxy({}, { ownKeys() { return ["x", "x"]; } });
|
|
try { Object.keys(duplicates); } catch (error) { console.log(error.name); }
|
|
const badKey = new Proxy({}, { ownKeys() { return [3]; } });
|
|
try { Object.keys(badKey); } catch (error) { console.log(error.name); }
|
|
const fixed = new Proxy({}, { getOwnPropertyDescriptor() { return { value: 1 }; } });
|
|
try { Object.hasOwn(fixed, "x"); } catch (error) { console.log(error.name); }
|
|
const plain = new Proxy({}, {});
|
|
console.log("toString" in plain, "absent" in plain, plain.absent === undefined);
|
|
const bare = new Proxy(Object.create(null), {});
|
|
console.log("toString" in bare, bare.toString === undefined);
|
|
const keys = ["first", "second"];
|
|
const snapshot = new Proxy({}, {
|
|
ownKeys() { return keys; },
|
|
getOwnPropertyDescriptor(target, key) {
|
|
keys[1] = "changed";
|
|
return { enumerable: true, configurable: true, value: key };
|
|
}
|
|
});
|
|
console.log(Object.keys(snapshot).join(","));
|
|
const protectedTarget = { visible: 2 };
|
|
Object.defineProperty(protectedTarget, "fixed", { value: -0 });
|
|
const protectedProxy = new Proxy(protectedTarget, {});
|
|
const protectedDescriptor = Object.getOwnPropertyDescriptor(protectedProxy, "fixed");
|
|
console.log(Object.keys(protectedProxy).join(","), protectedDescriptor.enumerable, protectedDescriptor.writable, protectedDescriptor.configurable, 1 / protectedDescriptor.value);
|
|
const readonlyGet = new Proxy(protectedTarget, { get() { return 0; } });
|
|
try { console.log(readonlyGet.fixed); } catch (error) { console.log(error.name); }
|
|
const readonlyHas = new Proxy(protectedTarget, { has() { return false; } });
|
|
try { console.log("fixed" in readonlyHas); } catch (error) { console.log(error.name); }
|
|
const readonlyKeys = new Proxy(protectedTarget, { ownKeys() { return ["visible"]; } });
|
|
try { Object.keys(readonlyKeys); } catch (error) { console.log(error.name); }
|
|
const readonlyDescriptor = new Proxy(protectedTarget, { getOwnPropertyDescriptor() { return; } });
|
|
try { Object.hasOwn(readonlyDescriptor, "fixed"); } catch (error) { console.log(error.name); }
|
|
const readonlySet = new Proxy(protectedTarget, { set() { return true; } });
|
|
try { readonlySet.fixed = 1; } catch (error) { console.log(error.name); }
|
|
const readonlyDelete = new Proxy(protectedTarget, { deleteProperty() { return true; } });
|
|
try { erase(readonlyDelete, "fixed"); } catch (error) { console.log(error.name); }
|
|
const exactDescriptor = new Proxy(protectedTarget, { getOwnPropertyDescriptor() { return { value: -0 }; } });
|
|
console.log(Object.hasOwn(exactDescriptor, "fixed"), 1 / Object.getOwnPropertyDescriptor(exactDescriptor, "fixed").value);
|
|
const showHidden = new Proxy(protectedTarget, {
|
|
getOwnPropertyDescriptor(target, key) {
|
|
if (key === "fixed") return { value: -0 };
|
|
return { value: 2, enumerable: true, configurable: true };
|
|
}
|
|
});
|
|
console.log(Object.keys(showHidden).join(","));
|