最近手头我的项目利用到了沙箱机制顺便钻研了下 间接上代码~
function sandbox(code) { code= 'with (sandbox) {' + code + '}' return new Function('sandbox', code)}let str = 'let a = 10;console.log(a)'sandbox(str)({})//而es6的proxy则能够解决这个问题,proxy能够设置拜访拦截器,于是with再加上proxy简直完满解决js沙箱机制。当然,还是有机制能够绕过,有大神发现Symbol.unScopables能够不受with的影响,所以要另外解决Symbol.unScopables:
class ProxySandbox{ constructor(){ const rawWindow = window const fakeWindow = {} const proxy = new Proxy(fakeWindow, { set(target,prop,value){ target[prop] = value return true }, get(target,prop){ return target[prop] || fakeWindow[prop] } }) this.proxy = proxy }}const sandbox1 = new ProxySandbox()const sandbox2 = new ProxySandbox()window.a = 1((window) => { window.a = 'hello' console.log(window.a)})(sandbox1.proxy)((window) => { window.a = 'world' console.log(window.a)})(sandbox1.proxy)
下面的例子利用到es6的proxy,目前js沙箱能做到的最好的沙箱机制,实用于多个利用,然而也有兼容性的限度
快照沙箱
class snapShotSandbox{ proxy = window // window 属性 modifyPropsMap = {} // 记录在window上的批改 active() active(){ // 激活沙箱 this.windowSnapshot = {} // 拍照 for(const prop in window){ if(window.hasOwnProperty(prop)){ this.windowSnapshot[prop] = window[prop] } } Object.keys(this.modifyPropsMap).forEach(prop => { window[prop] = this.modifyPropsMap[prop] }) } inactive(){ // 失活沙箱 for(const prop in window){ if(window.hasOwnProperty(prop)){ if(window[prop] !== this.windowSnapshot[prop]){ this.modifyPropsMap[prop] = window[prop] window[prop] = this.windowSnapshot[prop] } } } }}const sandbox = new snapShotSandbox() ((window) => { window.a = 1 window.b = 2 console.log(window.a, window.b) sandbox.inactive() console.log(window.a, window.b) sandbox.active() console.log(window.a, window.b)})(sandbox.proxy) // sandbox.proxy 就是 window
// 不反对多个子利用