Learning Record

2026年8月14日学习记录

记录于:2026-08-14

今日学习内容

今天学习了如何结合 JavaScript 的 with 语句和 Proxy 创建一个简单的运行沙盒,让代码优先从指定的沙盒对象中读取和修改变量,减少对全局作用域的直接影响。

实现思路

with 会把一个对象临时加入当前作用域链。配合 Proxy 后,可以拦截代码对变量的查询、读取和赋值操作,将这些操作限制在沙盒对象中。

function createSandbox(initialState = {}) {
  const sandbox = new Proxy(
    { ...initialState },
    {
      has() {
        return true;
      },
      get(target, key) {
        if (key === Symbol.unscopables) {
          return undefined;
        }

        return Reflect.get(target, key);
      },
      set(target, key, value) {
        return Reflect.set(target, key, value);
      },
    }
  );

  return {
    sandbox,
    run(code) {
      const execute = new Function("sandbox", `with (sandbox) { return (() => { ${code} })(); }`);

      return execute(sandbox);
    },
  };
}

const context = createSandbox({ count: 1 });

context.run("count += 1; message = 'hello';");

console.log(context.sandbox.count); // 2
console.log(context.sandbox.message); // hello
console.log(globalThis.message); // undefined

核心原理

  • with (sandbox) 让标识符优先在 sandbox 中查找
  • Proxyhas 拦截器让变量查询停留在沙盒对象中
  • getset 拦截器负责读取与保存沙盒中的变量
  • 每个沙盒使用独立对象,因此不同沙盒之间的状态不会直接混在一起

注意事项

with + Proxy 只能实现基础的作用域隔离,并不等于真正的安全沙盒:

  • 严格模式中不能使用 with
  • with 会让变量来源变得不清晰,也不利于 JavaScript 引擎优化
  • 如果向沙盒暴露了 windowglobalThisFunction 等对象,执行代码仍可能访问外部环境
  • 不应该使用这种方式执行不可信代码

如果需要执行不可信代码,应选择隔离能力更强的方案,例如浏览器中的 iframe、Web Worker,或者 Node.js 中经过安全评估的隔离方案。

今日总结

今天理解了 with 可以改变标识符的查找范围,而 Proxy 可以控制变量的读取和写入。两者结合后能够实现一个简单的 JavaScript 沙盒,适合学习作用域和微前端沙盒的基本原理,但不能作为真正的安全边界。