js中很容易出现全局变量污染的情况,全局变量需要依赖全局环境的命名空间,如果为了避免这种情况,
大多数采用多重命名空间的方式来定义变量,但是此种方式名称长度长,解析效率低。因此,可以采用一种
沙箱模式来管理我们的代码。
该模式创建了一个新的环境变量,所有的变量在该环境内可访问,环境外不可访问(前提是不隐式声明
全局变量如 a=123)。主要利用了函数形成的闭包。
具体的沙箱模式可以这样实现:
1 function Sandbox(){
2 if(!(this instanceof Sandbox)) return new Sandbox();
3 this.modules = {};
4 }
5 Sandbox.prototype = {
6 add: function(){
7 var args = [].slice.call(arguments);
8 var that = this;
9 if(args.length == 2 && typeof args[0] == "string" && typeof args[1] == "function"){
10 this.modules[args[0]] = function(){
11 args[1].call(that,that);
12 }
13 }else{
14 throw SyntaxError("arguments should be an string token and a function...")
15 }
16 },
17 use: function(){
18 var args = [].slice.call(arguments),
19 modules = this.modules;
20 var that = this, i,len;
21 var fn = args.pop();
22 args = typeof args[0] == "string" ? args : args[0];
23 if(args.length == 0 || args[0] == "*" ){
24 args = modules;
25 }
26 for(i=0,len=args.length;i<len;i++){
27 if(modules[args[i]]){
28 modules[args[i]]();
29 }else
30 continue;
31 }
32 fn(this);
33 }
34 }
35
36 function fn1(s){s.say = function(){console.log("f1...");}}
37 function fn2(s){s.speak = function(){console.log("f2...")}}
38 function fn3(){console.log("f3...")}
39
40 var s = Sandbox();
41 s.add("f1",fn1);
42 s.use("f1",function(s){
43 s.say();
44 var ss = Sandbox();
45 ss.add("f2",fn2);
46 ss.use("f2",function(s){
47 s.speak();
48 })
49 })
另外,jQuery的创建者之前提到过另一种在js执行引擎级别的代码隔离,即通过创建iframe,在另一个
全局空间内执行代码,这样原命名空间就不会受到污染。但是iframe的创建代价是很高的,而且如果iframe中
的脚本执行时间或者计算量很大,那么很容易消耗系统的资源。
1 var f = document.getElementById("f");
2 f.style.display = "none"
3 f.contentDocument.write("<script>parent.sandbox = function(s){eval(s)}<\/script>")
4 sandbox("a=3")