沙箱模式常见于YUI3 core,它是一种采用同一构造器(Constructor)生成彼此独立且互不干扰(self-contained)的实例对象,而从避免污染全局对象的方法。
命名空间
JavaScript本身中没有提供命名空间机制,所以为了避免不同函数、对象以及变量名对全局空间的污染,通常的做法是为你的应用程序或者库创建一个唯一的全局对象,然后将所有方法与属性添加到这个对象上。
代码清单1 : 传统命名空间模式
01 |
/* BEFORE: 5 globals */ |
09 |
module1.data = {a: 1, b: 2}; |
15 |
MYAPP.Parent = function() {}; |
16 |
MYAPP.Child = function() {}; |
22 |
MYAPP.modules.module1 = {}; |
23 |
MYAPP.modules.module1.data = {a: 1, b: 2}; |
24 |
MYAPP.modules.module2 = {}; |
在这段代码中,你创建了一个全局对象MYAPP,并将其他所有对象、函数作为属性附加到MYAPP上。
通常这是一种较好的避免命名冲突的方法,它被应用在很多项目中,但这种方法有一些缺点。
- 需要给所有需要添加的函数、变量加上前缀。
- 因为只有一个全局对象,这意味着一部分代码可以肆意地修改全局对象而导致其余代码的被动更新。
全局构造器
你可以用一个全局构造器,而不是一个全局对象,我们给这个构造器起名为Sandbox(),你可以用这个构造器创建对象,你还可以为构造器传递一个回调函数作为参数,这个回调函数就是你存放代码的独立沙箱环境。
代码清单2:沙箱的使用
1 |
new Sandbox(function(box){ |
让我们给沙箱添加点别的特性。
- 创建沙箱时可以不使用'new'操作符。
- Sandbox()构造器接受一些额外的配置参数,这些参数定义了生成对象所需模块的名称,我们希望代码更加模块化。
拥有了以上特性后,让我们看看怎样初始化一个对象。
代码清单3显示了你可以在不需要‘new’操作符的情况下,创建一个调用了'ajax'和'event'模块的对象。
代码清单3:以数组的形式传递模块名
1 |
Sandbox(['ajax', 'event'], function(box){ |
代码清单4:以独立的参数形式传递模块名
1 |
Sandbox('ajax', 'dom', function(box){ |
代码清单5显示了你可以把通配符'*'作为参数传递给构造器,这意味着调用所有可用的模块,为了方便起见,如果没有向构造器传递任何模块名作为参数,构造器会把'*'作为缺省参数传入。
代码清单5:调用所用可用模块
1 |
Sandbox('*', function(box){ |
代码清单6显示你可以初始化沙箱对象多次,甚至你可以嵌套它们,而不用担心彼此间会产生任何冲突。
代码清单6:嵌套的沙箱实例
01 |
Sandbox('dom', 'event', function(box){ |
02 |
// work with dom and event |
03 |
Sandbox('ajax', function(box) { |
04 |
// another sandboxed "box" object |
05 |
// this "box" is not the same as |
06 |
// the "box" outside this function |
10 |
// no trace of Ajax module here |
从上面这些示例可以看出,使用沙箱模式,通过把所有代码逻辑包裹在一个回调函数中,你根据所需模块的不同生成不同的实例,而这些实例彼此互不干扰独立的工作着,从而保护了全局命名空间。
现在让我们看看怎样实现这个Sandbox()构造器。
添加模块
在实现主构造器之前,让我们看看如何向Sandbox()构造器中添加模块。
因为Sandbox()构造器函数也是对象,所以你可以给它添加一个名为’modules'的属性,这个属性将是一个包含一组键值对的对象,其中每对键值对中Key是需要注册的模块名,而Value则是该模块的入口函数,当构造器初始化时当前实例会作为第一个参数传递给入口函数,这样入口函数就能为该实例添加额外的属性与方法。
在代码清单7中,我们添加了'dom','event','ajax'模块。
代码清单7:注册模块
02 |
Sandbox.modules.dom = function(box) { |
03 |
box.getElement = function() {}; |
04 |
box.getStyle = function() {}; |
07 |
Sandbox.modules.event = function(box) { |
08 |
// access to the Sandbox prototype if needed: |
09 |
// box.constructor.prototype.m = "mmm"; |
10 |
box.attachEvent = function(){}; |
11 |
box.dettachEvent = function(){}; |
13 |
Sandbox.modules.ajax = function(box) { |
14 |
box.makeRequest = function() {}; |
15 |
box.getResponse = function() {}; |
实现构造器
代码清单8描述了实现构造器的方法,其中关键的几个要点:
- 我们检查this是否为Sandbox的实例,若不是,证明Sandbox没有被new操作符调用,我们将以构造器方式重新调用它。
- 你可以在构造器内部为this添加属性,同样你也可以为构造器的原型添加属性。
- 模块名称会以数组、独立参数、通配符‘*’等多种形式传递给构造器。
- 请注意在这个例子中我们不需要从外部文件中加载模块,但在诸如YUI3中,你可以仅仅加载基础模块(通常被称作种子(seed)),而其他的所有模块则会从外部文件中加载。
- 一旦我们知道了所需的模块,并初始化他们,这意味着调用了每个模块的入口函数。
- 回调函数作为参数被最后传入构造器,它将使用最新生成的实例并在最后执行。
代码清单8:实现Sandbox构造器
03 |
// turning arguments into an array |
04 |
var args = Array.prototype.slice.call(arguments), |
05 |
// the last argument is the callback |
06 |
callback = args.pop(), |
07 |
// modules can be passed as an array or as individual parameters |
08 |
modules = (args[0] && typeof args[0] === "string") ? |
11 |
// make sure the function is called |
13 |
if (!(this instanceof Sandbox)) { |
14 |
return new Sandbox(modules, callback); |
16 |
// add properties to 'this' as needed: |
19 |
// now add modules to the core 'this' object |
20 |
// no modules or "*" both mean "use all modules" |
21 |
if (!modules || modules === '*') { |
23 |
for (i in Sandbox.modules) { |
24 |
if (Sandbox.modules.hasOwnProperty(i)) { |
29 |
// init the required modules |
30 |
for (i = 0; i < modules.length; i++) { |
31 |
Sandbox.modules[modules[i]](this); |
36 |
// any prototype properties as needed |
38 |
name: "My Application", |
- 一种JavaScript 类的设计模式
一种JavaScript 类的设计模式尽管前面介绍了如何定义一个类,如何初始化一个类的实例,但既可以在function定义的函数体中添加成员,又可以用prototype 定义类的成员,代码显的很混乱, ...
- JavaScript 中常见设计模式整理
开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式.本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知. JavaScript 中常见设计模 ...
- Javascript常用的设计模式详解
Javascript常用的设计模式详解 阅读目录 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javas ...
- 关于JavaScript的沙箱模式
从语言学的角度上来说,允许代码无节制地使用全局变量,是最错误的选择之一.而更可怕的,就是一个变量"可能"成为全局的(在未知的时间与地点).但是这两项,却伴随JavaScript这门 ...
- 关于javascript的沙箱模式以及缓存方法
在javascript函数代码中,经常会不经意出现全局变量,很可能造成对全局对象的污染,由于这种弊端的存在,那么沙箱模式油然而生.沙箱模式又称为沙盒模式.隔离模式.在js中只有函数可以限定变量作用域, ...
- javascript学习(9)——[设计模式]单例
单例模式,相信大家对此都不陌生,我们主要讲下javascript中几个比较常见的设计模式: (1).普通的单体 (2).具有局部变量的强大单体 (3).惰性单体 (4).分支单体 下面我们就一一进行介 ...
- GOF提出的23种设计模式是哪些 设计模式有创建形、行为形、结构形三种类别 常用的Javascript中常用设计模式的其中17种 详解设计模式六大原则
20151218mark 延伸扩展: -设计模式在很多语言PHP.JAVA.C#.C++.JS等都有各自的使用,但原理是相同的,比如JS常用的Javascript设计模式 -详解设计模式六大原则 设计 ...
- javascript 对象的设计模式
1.为什么学习设计模式:http://www.iteye.com/news/32092 或 https://blog.csdn.net/pigpigpig4587/article/details ...
- 写的一个轻量级javascript框架的设计模式
公司一直使用jQuery框架,一些小的项目还是觉得jQuery框架太过于强大了,于是自己周末有空琢磨着写个自己的框架.谈到js的设计模式,不得不说说js的类继承机制,javascript不同于PHP可 ...
随机推荐
- 什么是Spark
什么是Spark Apache Spark是一个开源集群运算框架, 相对于Hadoop的MapReduce会在运行完工作后将中介数据存放到磁盘中,Spark使用了存储器内运算技术,能在数据尚未写入硬盘 ...
- 【MFC】学习与问题整合
需要源码联系邮件:kangxlchn@163.com 1.新建一个MFC工程(基于对话框) 环境:vs2017 统统NEXT 新建完成后打开MFCPrj.cpp文件 打开类试图 每创建一个MFC项目, ...
- PAT-甲级解题目录
PAT甲级题目:点这里 pat解题列表 题号 标题 题目类型 10001 1001 A+B Format (20 分) 字符串处理 1003 1003 Emergency (25 分) 最短路径 ...
- Kali信息收集-DNS
1.whois查询 直接在终端输入whois 域名 2.查找dns服务器 (1)host (2)dig (3)nslookup 3.域传输 4.域名枚举 (1)dnsdict6 kali没有集成这款工 ...
- 6.azkban的监控
azkaban自带的监控flow自带的邮件功能SLA总结写程序监控job情况监控azkaban的元数据库使用azkaban API监控总结 azkaban自带的监控 azkban目前仅仅支持邮件监控, ...
- BZOJ 4176 Lucas的数论 莫比乌斯反演+杜教筛
题意概述:求,n<=10^9,其中d(n)表示n的约数个数. 分析: 首先想要快速计算上面的柿子就要先把d(ij)表示出来,有个神奇的结论: 证明:当且仅当a,b没有相同的质因数的时候我们统计其 ...
- Java学习个人备忘录之异常
概述 异常:是在运行时期发生的不正常情况. 在java中用类的形式对不正常情况进行了描述和封装对象. 描述不正常的情况的类,就称为异常类. 以前正常流程代码和问题处理代码相结合,现在将正常流程代码和问 ...
- java实现屏幕共享的小程序
最近在做软件软件工程的课程设计,做一个用于实验室的屏幕监控系统,参考各种前人代码,最后领悟之后要转换自己的代码,初学者都是这样模仿过来的. 说到屏幕监控系统,有教师断和学生端, ...
- P4语法(2) Parser
这里参考学习了: P4语言规范 P4台湾社群 Parser 关于parser 在P4程序中,有着大量的首部(header)和首部实例,但每次只有部分首部实例会对数据包进行操作,而parser会用于生成 ...
- 第三章——供机器读取的数据(CSV与JSON)
本书使用的文件.代码:https://github.com/huangtao36/data_wrangling 机器可读(machine readable)文件格式: 1.逗号分隔值(Comma-Se ...