沙箱模式常见于YUI3 core,它是一种采用同一构造器(Constructor)生成彼此独立且互不干扰(self-contained)的实例对象,而从避免污染全局对象的方法。

命名空间

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

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

01 /* BEFORE: 5 globals */
02 // constructors
03 function Parent() {}
04 function Child() {}
05 // a variable
06 var some_var = 1;
07 // some objects
08 var module1 = {};
09 module1.data = {a: 1, b: 2};
10 var module2 = {};
11 /* AFTER: 1 global */
12 // global object
13 var MYAPP = {};
14 // constructors
15 MYAPP.Parent = function() {};
16 MYAPP.Child = function() {};
17 // a variable
18 MYAPP.some_var = 1;
19 // an object
20 MYAPP.modules = {};
21 // nested objects
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){
2     // your code here...
3 });

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

  1. 创建沙箱时可以不使用'new'操作符。
  2. Sandbox()构造器接受一些额外的配置参数,这些参数定义了生成对象所需模块的名称,我们希望代码更加模块化。

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

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

代码清单3:以数组的形式传递模块名

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

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

1 Sandbox('ajax''dom'function(box){
2     // console.log(box);
3 });

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

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

1 Sandbox('*'function(box){
2     // console.log(box);
3 });
4 Sandbox(function(box){
5     // console.log(box);
6 });

代码清单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
07     //...
08     // done with Ajax
09     });
10     // no trace of Ajax module here
11 });

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

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

添加模块

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

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

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

代码清单7:注册模块

01 Sandbox.modules = {};
02 Sandbox.modules.dom = function(box) {
03     box.getElement = function() {};
04     box.getStyle = function() {};
05     box.foo = "bar";
06 };
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(){};
12 };
13 Sandbox.modules.ajax = function(box) {
14     box.makeRequest = function() {};
15     box.getResponse = function() {};
16 };

实现构造器

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

  1. 我们检查this是否为Sandbox的实例,若不是,证明Sandbox没有被new操作符调用,我们将以构造器方式重新调用它。
  2. 你可以在构造器内部为this添加属性,同样你也可以为构造器的原型添加属性。
  3. 模块名称会以数组、独立参数、通配符‘*’等多种形式传递给构造器。
  4. 请注意在这个例子中我们不需要从外部文件中加载模块,但在诸如YUI3中,你可以仅仅加载基础模块(通常被称作种子(seed)),而其他的所有模块则会从外部文件中加载。
  5. 一旦我们知道了所需的模块,并初始化他们,这意味着调用了每个模块的入口函数。
  6. 回调函数作为参数被最后传入构造器,它将使用最新生成的实例并在最后执行。

代码清单8:实现Sandbox构造器

01 <script>
02 function 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") ?
09     args : args[0],
10     i;
11     // make sure the function is called
12     // as a constructor
13     if (!(this instanceof Sandbox)) {
14         return new Sandbox(modules, callback);
15     }
16     // add properties to 'this' as needed:
17     this.a = 1;
18     this.b = 2;
19     // now add modules to the core 'this' object
20     // no modules or "*" both mean "use all modules"
21     if (!modules || modules === '*') {
22         modules = [];
23             for (i in Sandbox.modules) {
24                 if (Sandbox.modules.hasOwnProperty(i)) {
25                     modules.push(i);
26             }
27         }
28     }
29     // init the required modules
30     for (i = 0; i < modules.length; i++) {
31         Sandbox.modules[modules[i]](this);
32     }
33     // call the callback
34     callback(this);
35 }
36 // any prototype properties as needed
37 Sandbox.prototype = {
38     name: "My Application",
39     version: "1.0",
40     getName: function() {
41         return this.name;
42     }
43 };
44 </script>

JavaScript SandBox沙箱设计模式的更多相关文章

  1. 一种JavaScript 类的设计模式

    一种JavaScript 类的设计模式尽管前面介绍了如何定义一个类,如何初始化一个类的实例,但既可以在function定义的函数体中添加成员,又可以用prototype 定义类的成员,代码显的很混乱, ...

  2. JavaScript 中常见设计模式整理

    开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式.本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知. JavaScript 中常见设计模 ...

  3. Javascript常用的设计模式详解

    Javascript常用的设计模式详解 阅读目录 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javas ...

  4. 关于JavaScript的沙箱模式

    从语言学的角度上来说,允许代码无节制地使用全局变量,是最错误的选择之一.而更可怕的,就是一个变量"可能"成为全局的(在未知的时间与地点).但是这两项,却伴随JavaScript这门 ...

  5. 关于javascript的沙箱模式以及缓存方法

    在javascript函数代码中,经常会不经意出现全局变量,很可能造成对全局对象的污染,由于这种弊端的存在,那么沙箱模式油然而生.沙箱模式又称为沙盒模式.隔离模式.在js中只有函数可以限定变量作用域, ...

  6. javascript学习(9)——[设计模式]单例

    单例模式,相信大家对此都不陌生,我们主要讲下javascript中几个比较常见的设计模式: (1).普通的单体 (2).具有局部变量的强大单体 (3).惰性单体 (4).分支单体 下面我们就一一进行介 ...

  7. GOF提出的23种设计模式是哪些 设计模式有创建形、行为形、结构形三种类别 常用的Javascript中常用设计模式的其中17种 详解设计模式六大原则

    20151218mark 延伸扩展: -设计模式在很多语言PHP.JAVA.C#.C++.JS等都有各自的使用,但原理是相同的,比如JS常用的Javascript设计模式 -详解设计模式六大原则 设计 ...

  8. javascript 对象的设计模式

    1.为什么学习设计模式:http://www.iteye.com/news/32092   或  https://blog.csdn.net/pigpigpig4587/article/details ...

  9. 写的一个轻量级javascript框架的设计模式

    公司一直使用jQuery框架,一些小的项目还是觉得jQuery框架太过于强大了,于是自己周末有空琢磨着写个自己的框架.谈到js的设计模式,不得不说说js的类继承机制,javascript不同于PHP可 ...

随机推荐

  1. Unity编辑器 - DragAndDrop拖拽控件

    Unity编辑器 - DragAndDrop拖拽控件 Unity编辑器的拖拽(DragAndDrop)在网上能找到的资料少,自己稍微研究了一下,写了个相对完整的案例,效果如下 代码: object d ...

  2. 【hidden】微信小程序hidden属性使用示例

    hidden属性用于隐藏标签,代码示例: <view hidden="{{!statusTag}}">我出来了~</view> <button bin ...

  3. 使用JavaScript判断手机是处于横屏还是竖屏

    移动端的浏览器一般都支持window.orientation这个参数,通过这个参数可以判断出手机是处在横屏还是竖屏状态.从而根据实际需求而执行相应的程序.通过添加监听事件onorientationch ...

  4. 下落的树叶 (The Falling Leaves UVA - 699)

    题目描述: 原题:https://vjudge.net/problem/UVA-699 题目思路: 1.依旧二叉树的DFS 2.建树过程中开个数组统计 //紫书源代码WA AC代码: #include ...

  5. Font Awesome 完美的图标字体

    好久没来,虽说鄙人的人气不咋地,但还是很想念自己这一亩二分田地. 近期用在平台开发中,看着设计师摆开阵势,准备大画图标,想着自己将会很KUBI拼凑css-sprite图片,接着写一大堆 class^= ...

  6. vs_code 快捷键

    一般的Ctrl+Shift+P,F1显示命令面板按Ctrl+P快速打开,到文件.Ctrl + Shift + N新窗口/实例Ctrl + Shift + W /关闭窗口实例Ctrl +.用户设置Ctr ...

  7. 【转载】OpenCV(C++ 与 Python 的比较)与 MATLAB 的比较

    原文作者 : Satya Mallick 译者 : aleen42 原文  https://aleen42.gitbooks.io/personalwiki/content/translation/o ...

  8. Python3 小工具-ICMP扫描

    from scapy.all import * import optparse import threading import os def scan(ipt): pkt=IP(dst=ipt)/IC ...

  9. Python中的赋值语法

    Python中复制语法有6种 Basic Form >>>spam = 'spam' Tuple assignment >>>spam, ham = 'spam', ...

  10. Ubuntu 基础操作 基础命令 热键 man手册使用 关机 重启等命令使用

    . : 关机, 如果将Linux默认运行等级设置为0, 系统将无法启动; -- : 多用户模式, 允许使用网络文件系统, 一般不使用图形界面登陆就是这种模式; -- : 多用户图形界面模式, 该模式下 ...