JavaScript 设计模式 安全沙箱模式


Posted in Javascript onSeptember 24, 2010

命名空间

JavaScript本身中没有提供命名空间机制,所以为了避免不同函数、对象以及变量名对全局空间的污染,通常的做法是为你的应用程序或者库创建一个唯一的全局对象,然后将所有方法与属性添加到这个对象上。

/* BEFORE: 5 globals */ 
// constructors 
function Parent() {} 
function Child() {} 
// a variable 
var some_var = 1; 
// some objects 
var module1 = {}; 
module1.data = {a: 1, b: 2}; 
var module2 = {}; 
/* AFTER: 1 global */ 
// global object 
var MYAPP = {}; 
// constructors 
MYAPP.Parent = function() {}; 
MYAPP.Child = function() {}; 
// a variable 
MYAPP.some_var = 1; 
// an object 
MYAPP.modules = {}; 
// nested objects 
MYAPP.modules.module1 = {}; 
MYAPP.modules.module1.data = {a: 1, b: 2}; 
MYAPP.modules.module2 = {};

代码清单1 : 传统命名空间模式

在这段代码中,你创建了一个全局对象MYAPP,并将其他所有对象、函数作为属性附加到MYAPP上.

通常这是一种较好的避免命名冲突的方法,它被应用在很多项目中,但这种方法有一些缺点。

1.需要给所有需要添加的函数、变量加上前缀。

2.因为只有一个全局对象,这意味着一部分代码可以肆意地修改全局对象而导致其余代码的被动更新。

全局构造器

你可以用一个全局构造器,而不是一个全局对象,我们给这个构造器起名为Sandbox(),你可以用这个构造器创建对象,你还可以为构造器传递一个回调函数作为参数,这个回调函数就是你存放代码的独立沙箱环境。

new Sandbox(function(box){ 
 // your code here... 
});

代码清单2:沙箱的使用

让我们给沙箱添加点别的特性

1.创建沙箱时可以不使用'new'操作符

2.Sandbox()构造器接受一些额外的配置参数,这些参数定义了生成对象所需模块的名称,我们希望代码更加模块化。

拥有了以上特性后,让我们看看怎样初始化一个对象。

代码清单3显示了你可以在不需要‘new'操作符的情况下,创建一个调用了'ajax'和'event'模块的对象.

Sandbox(['ajax', 'event'], function(box){ 
 // console.log(box); 
});

代码清单3:以数组的形式传递模块名
Sandbox('ajax', 'dom', function(box){ 
 // console.log(box); 
});

代码清单4:以独立的参数形式传递模块名

代码清单5显示了你可以把通配符'*'作为参数传递给构造器,这意味着调用所有可用的模块,为了方便起见,如果没有向构造器传递任何模块名作为参数,构造器会把'*'作为缺省参数传入.

Sandbox('*', function(box){ 
 // console.log(box); 
}); 
Sandbox(function(box){ 

 // console.log(box); 
});

代码清单5:调用所用可用模块

代码清单6显示你可以初始化沙箱对象多次,甚至你可以嵌套它们,而不用担心彼此间会产生任何冲突.

Sandbox('dom', 'event', function(box){ 
// work with dom and event 
 Sandbox('ajax', function(box) { 

 // another sandboxed "box" object 

// this "box" is not the same as 

// the "box" outside this function 

//... 

// done with Ajax 

 }); 
// no trace of Ajax module here 
});

代码清单6:嵌套的沙箱实例

从上面这些示例可以看出,使用沙箱模式,通过把所有代码逻辑包裹在一个回调函数中,你根据所需模块的不同生成不同的实例,而这些实例彼此互不干扰独立的工作着,从而保护了全局命名空间。

现在让我们看看怎样实现这个Sandbox()构造器.

添加模块

在实现主构造器之前,让我们看看如何向Sandbox()构造器中添加模块。

因为Sandbox()构造器函数也是对象,所以你可以给它添加一个名为'modules'的属性,这个属性将是一个包含一组键值对的对象,其中每对键值对中Key是需要注册的模块名,而Value则是该模块的入口函数,当构造器初始化时当前实例会作为第一个参数传递给入口函数,这样入口函数就能为该实例添加额外的属性与方法。

在代码清单7中,我们添加了'dom','event','ajax'模块。

Sandbox.modules = {}; 
Sandbox.modules.dom = function(box) { 
box.getElement = function() {}; 

box.getStyle = function() {}; 

box.foo = "bar"; 
}; 
Sandbox.modules.event = function(box) { 
// access to the Sandbox prototype if needed: 
// box.constructor.prototype.m = "mmm"; 

 box.attachEvent = function(){}; 

box.dettachEvent = function(){}; 
}; 
Sandbox.modules.ajax = function(box) { 

box.makeRequest = function() {}; 

box.getResponse = function() {}; 
};

代码清单7:注册模块

实现构造器

代码清单8描述了实现构造器的方法,其中关键的几个要点:

1.我们检查this是否为Sandbox的实例,若不是,证明Sandbox没有被new操作符调用,我们将以构造器方式重新调用它。

2.你可以在构造器内部为this添加属性,同样你也可以为构造器的原型添加属性。

3.模块名称会以数组、独立参数、通配符‘*'等多种形式传递给构造器。

4.请注意在这个例子中我们不需要从外部文件中加载模块,但在诸如YUI3中,你可以仅仅加载基础模块(通常被称作种子(seed)),而其他的所有模块则会从外部文件中加载。

5.一旦我们知道了所需的模块,并初始化他们,这意味着调用了每个模块的入口函数。

6.回调函数作为参数被最后传入构造器,它将使用最新生成的实例并在最后执行。

function Sandbox() { 
 // turning arguments into an array 

 var args = Array.prototype.slice.call(arguments), 

 // the last argument is the callback 


 callback = args.pop(), 

 // modules can be passed as an array or as individual parameters 


 modules = (args[0] && typeof args[0] === "string") ? 


args : args[0], 


i; 


 // make sure the function is called 


// as a constructor 

 if (!(this instanceof Sandbox)) { 


 return new Sandbox(modules, callback); 

} 

// add properties to 'this' as needed: 

this.a = 1; 

this.b = 2; 

// now add modules to the core 'this' object 

// no modules or "*" both mean "use all modules" 

if (!modules || modules === '*') { 


modules = []; 


for (i in Sandbox.modules) { 



if (Sandbox.modules.hasOwnProperty(i)) { 




modules.push(i); 



} 


 } 

 } 

// init the required modules 

for (i = 0; i < modules.length; i++) { 


Sandbox.modules[modules[i]](this); 

} 

// call the callback 

callback(this); 
} 
// any prototype properties as needed 
Sandbox.prototype = { 

name: "My Application", 

version: "1.0", 

getName: function() { 


return this.name; 

} 
};

代码清单8:实现Sandbox构造器
原文来自:Stoyan Stefanov - JavaScript Patterns Part 7:The Sandbox Pattern
Javascript 相关文章推荐
Ucren Virtual Desktop V2.0
Nov 07 Javascript
JavaScript入门教程(12) js对象化编程
Jan 31 Javascript
ASP.NET jQuery 实例11 通过使用jQuery validation插件简单实现用户登录页面验证功能
Feb 03 Javascript
js阻止默认事件与js阻止事件冒泡示例分享 js阻止冒泡事件
Jan 27 Javascript
JS实现部分HTML固定页面顶部随屏滚动效果
Dec 24 Javascript
如何解决easyui自定义标签 datagrid edit combobox 手动输入保存不上
Dec 26 Javascript
原生JS实现匀速图片轮播动画
Oct 18 Javascript
node.js学习之断言assert的使用示例
Sep 28 Javascript
vue过滤器用法实例分析
Mar 15 Javascript
详解Vue前端对axios的封装和使用
Apr 01 Javascript
JavaScript中的this基本问题实例小结
Mar 09 Javascript
vue iview 隐藏Table组件里的某一列操作
Nov 13 Javascript
IE无法设置短域名下Cookie
Sep 23 #Javascript
Javascript中获取出错代码所在文件及行数的代码
Sep 23 #Javascript
基于JQuery的一个简单的鼠标跟随提示效果
Sep 23 #Javascript
用js模拟JQuery的show与hide动画函数代码
Sep 20 #Javascript
通过DOM脚本去设置样式信息
Sep 19 #Javascript
javscript对象原型的一些看法
Sep 19 #Javascript
Ext 今日学习总结
Sep 19 #Javascript
You might like
PHP中动态显示签名和ip原理
2007/03/28 PHP
Smarty变量调节器失效的解决办法
2014/08/20 PHP
php经典算法集锦
2015/11/14 PHP
php文件操作之文件写入字符串、数组的方法分析
2019/04/15 PHP
laravel Model 执行事务的实现
2019/10/10 PHP
基于laravel缓冲cache的用法详解
2019/10/23 PHP
Javascript(AJAX)解析XML的代码(兼容FIREFOX/IE)
2010/07/11 Javascript
简单常用的幻灯片播放实现代码
2013/09/25 Javascript
JS实现金额转换(将输入的阿拉伯数字)转换成中文的实现代码
2013/09/30 Javascript
JS实现点击图片在当前页面放大并可关闭的漂亮效果
2013/10/18 Javascript
浅析JSONP技术原理及实现
2016/06/08 Javascript
百度多文件异步上传控件webuploader基本用法解析
2016/11/07 Javascript
详解为Angular.js内置$http服务添加拦截器的方法
2016/12/20 Javascript
vue 实现 ios 原生picker 效果及实现思路解析
2017/12/06 Javascript
详解VueJS应用中管理用户权限
2018/02/02 Javascript
JavaScript实现多叉树的递归遍历和非递归遍历算法操作示例
2018/02/08 Javascript
vue中的provide/inject的学习使用
2018/05/09 Javascript
微信小程序按钮去除边框线分享页面功能
2018/08/27 Javascript
浅析Vue.js 中的条件渲染指令
2018/11/19 Javascript
vue项目首屏加载时间优化实战
2019/04/23 Javascript
Layui事件监听的实现(表单和数据表格)
2019/10/17 Javascript
使用vuex较为优雅的实现一个购物车功能的示例代码
2019/12/09 Javascript
three.js 实现露珠滴落动画效果的示例代码
2021/03/01 Javascript
python实现图片批量压缩程序
2018/07/23 Python
python 删除字符串中连续多个空格并保留一个的方法
2018/12/22 Python
Python 监测文件是否更新的方法
2019/06/10 Python
树莓派安装OpenCV3完整过程的实现
2019/10/10 Python
Bogner美国官网:滑雪服中的”Dior”
2018/01/30 全球购物
苹果音乐订阅:Apple Music
2018/08/02 全球购物
俄罗斯连接商品和买家的在线平台:goods.ru
2020/11/30 全球购物
JVM是一个编译程序还是解释程序
2012/09/11 面试题
劲霸男装广告词改编版
2014/03/21 职场文书
市场营销策划方案
2014/06/11 职场文书
秀!学妹看见都惊呆的Python小招数!【详细语言特性使用技巧】
2021/04/27 Python
python中__slots__节约内存的具体做法
2021/07/04 Python
Java完整实现记事本代码
2022/06/16 Java/Android