If you're using anonymous iframes today to "evaluate" javascript code in a different realm, you can replace it with a new Realm, as a more performant option, e.g.:
const globalOne = window;
let iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const globalTwo = iframe.contentWindow;
will become:
const globalOne = window;
const globalTwo = new Realm().global;
This operation should be equivalent, in both scenarios:
globalOne.eval('1 + 2'); // yield 3
globalTwo.eval('1 + 2'); // yield 3
This operation should be equivalent, in both scenarios:
globalOne.eval('eval("1 + 2")'); // yield 3
globalTwo.eval('eval("1 + 2")'); // yield 3
Considering that you're creating a brand new realm, with its brand new global variable, the identity discontinuity is still present, just like in the iframe example:
let a1 = globalOne.eval('[1,2,3]');
let a2 = globalTwo.eval('[1,2,3]');
a1.prototype === a2.prototype; // yield false
a1 instanceof globalTwo.Array; // yield false
a2 instanceof globalOne.Array; // yield false
Note: There is not solution for this with iframes, the only possible partial-solution is to use with
statement which has some performance implications. With the Realm API, you will have more flexibility to avoid this issue.
If you attempt to evaluate code that uses something other than EcmaScript intrinsics, the code will fail to evaluate in the realm without the proper configuration, e.g.:
globalOne.eval('console.log(1)'); // yield a log message: "1"
globalTwo.eval('console.log(1)'); // throw an error: console is undefined
To solve this, you can add a new global binding in the realm that implements the console
API, e.g.:
globalTwo.console = globalOne.console;
Note: keep in mind that this will provide authority for code in the realm to walk its
way up into the globalOne object by using the prototype chain of the new global called
console
, e.g.:
globalTwo.eval('console.log.constructor("return this")()') === globalOne; // yield true
Instead, you can provide a fully functional console
API that closes over to the outer realm's console object. This way you don't leak authority to the newly created Realm.
If you're using node's vm
module today to "evaluate" javascript code in a different realm, you can replace it with a new Realm, e.g.:
const vm = require('vm');
const script = new vm.Script('this');
const globalOne = global;
const globalTwo = script.runInContext(new vm.createContext());
will become:
const globalOne = global;
const globalTwo = new Realm().global;
Note: these two are equivalent in functionality.