JS如何给函数一个纯净的作用域?

如题:假设我这边需要执行一个系统外传入的函数,但又害怕函数访问到系统内的变量导致随意更改。
如何让函数访问不到内部的变量?(只访问到指定的,系统传入的变量)
如:

var a = 1
var actions = {
  getA(){
      return a
  }
}
// eval中运行的就是系统外传入的函数
// 如何让它能访问到actions,而访问不到a?
// eval只是演示,能实现效果就行
eval('function(){alert(a)}')

10:26补充
可以用Function方式,运行动态函数。各方面都挺符合的,但是访问指定变量需要用this。
补充:用Function照样还是可以访问全局作用域的....

new Function('console.log(this)').apply({a:1})

访问a需要用this,有没有可以不用this直接使用a的方式?

回复
阅读 1.1k
5 个回答

这里使用 eval 能访问到 a 和 actions 的原因其实很简单:

  1. eval 会共享作用域,即 eval 执行的代码也能访问到 eval 调用时所在的作用域。
  2. 因此, 要解决这个问题只要将 a 从 eval 执行 时的作用域中隔离出去即可

可以参考如下方式

// actions.js
let a = 1;

export default {
  getA(){
      return a
  }
}
// main.js
import actions from './actions.js';

eval('function(){alert(a)}')

另外 new Function 的方式其实是支持传参数的

const a = 1;
new Function('a', 'console.log(a)')(a);

没有好的解决办法,闭包形成一个命名空间吧,但还是不能避免访问到全局变量的。

var test = (function () {
  var pluginName = '你好'
  return {
    say: function (desc) {
      var res = pluginName + ' => ' + desc
      console.log(res)
      return res
    }
  }
})();

eval('test.say("张三")')

使用with+new Function试试

既然说Function方式可行,那可以扩展一下,在用户代码上再包一层试试

new Function(`(function(a, b, c){ ${ userCode } }).apply(this, arguments)`).apply({a:1}, [1, 2, 3])

生成一些参数供用户代码用

p.s. 感觉这个场景用eval不是很合适

用iframe隔离

window.a=123
var frame = document.createElement('iframe')
frame.style.display='none'
document.body.append(frame)
frame.contentWindow.a=456
new frame.contentWindow.Function('w','console.log(w.a);console.log(window.a)')(window);
// 123
// 456
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏