zoukankan      html  css  js  c++  java
  • JavaScript基础对象创建模式之沙盘模式(026)

    沙盘模式可以弥补命名空间模式中的两项不足之处:

    • 使用唯一全局对象作为程序的全局变量入口,使得无法在同一程序中使用两个不同版本的API,因此它们使用的是同一个唯一的全局对象名,如MYAPP;
    • 较长的嵌套对象使得代码编写和解析都比较慢;
    沙盘模式,正如其名字所说,提供了一个各类模块可以共同“游戏”的环境,模块之间和沙盘之间不会相互影响。
    这种模式在YUI3中大量被使用。下面介绍一种沙盘模式的实现方式:
    1. 全局的构造函数
    在命名空间模式中只有一个全局对象;在沙盘模式中,唯一的是一个全局的构造函数:比如说,Sandbox()。Sandbox只是本例使用的名字,程序里应该使用一个有具体含义的名字。这个全局的构造函数接受一个回调函数,并为这个回调函数提供沙盘环境。
    沙盘构造函数的调用大概是这样的:
    new Sandbox(function (box) {
        // your code here...
    });
    
    对象box就好像命名空间模式中的MYAPP,提供了程序库当中需要的功能。
    然后再向沙盘模式加入两样技术:
    使用之前提到的检查方法,保证总是用new来调用沙盘构造函数;
    沙盘构造函数接受参数,来告知沙盘内应提供哪些模块的功能;
    有了这两个技术,我们会检查出Sandbox()不用new来调用,并在Sandbox()内部再用new来调用它自己:保证它总是用new来调用的;并传入适当的参数来通知沙盘提供相应的功能。这样,Sanbox()的调用过程就变成了这样:
    Sandbox(['ajax', 'event'], function (box) {
        // console.log(box);
    });
    
    也可以把要在沙盘中提供的功能模块的名字分别用两个(或多个)参数传入沙盘函数:
    Sandbox('ajax', 'dom', function (box) {
        // console.log(box);
    });
    
    如果程序中有许多模块,并希望一次全部支持所有模块的功能,可以用“*”来代替所有的模块名字,或者更简单地,省略模块名的参数来表示需要所有模块:
    Sandbox('*', function (box) {
        // console.log(box);
    });
    Sandbox(function (box) {
        // console.log(box);
    });
    
    沙盘模式应该足够灵活,并支持在沙盘的回调函数中再次使用沙盘函数:
    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
    });
    
    以上的例子做法其实就是把需要的功能模块的名字告诉沙盘函数,并把代码段写在回调函数里。这就可以在不形成全局变量污染的情况下,向不同的代码段提供其所需的模块功能支持。被Sandbox()创建的对象相互独立并依赖于不同的功能模块。另外,由于Sandbox是函数,因此它也是对象,所以还可以向Sandbox()加入静态属性来存放一些数据。
    2. 定义模块
    在 介绍Sandbox的实现之前,先看看如何定义模块。在沙盘模式中,全局的构造函数Sandbox是个函数对象,因此可以为它加入一个静态的属性来保存各 个模块,比如modules。modules是Sandbox的成员属性,也是一个对象,它通过内部的键值对来保存模块,键作为模块名,而值是模块的实 现。定义模块的做法是这样的:
    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 () {};
    };
    
    上面的例子里,我们给modules对象加入了三个模块,分别是dom,event,以及ajax。
    3. 实现Sandbox的沙盘构造函数
    一个可行的Sandbox构造函数是这样的(实际上,在你的程序里可能需要把Sandbox改成有意义的名字):
    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);
                }
            }
        }
        // initialize the required modules
        for (i = 0; i < modules.length; i += 1) {
            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;
        }
    };
    
    上面实现里的关键内容包括:
    • 检查this是不是Sandbox的实例,如果不是(说明不是用new调用的Sandbox())就再次用new调用Sandbox;
    • 可以用this为构造函数添加属性,也可以通过prototype来添加属性;
    • 需要使用的模块可以通过模块名的数组传入,也可以使用每个参数一个模块名的方式传入,“*”匹配所有支持的模块(实际的使用中可以还需要引入定义所需模块的js文件);
    • 如果所需的模块已经定义了,就初始化它,也就是执行定义模块的函数;
    • Sandbox函数的最后一个参数是个回调函数,它在Sandbox函数的最后被调用,并使用Sandbox创建的对象来执行相应的代码,这些代码就像在一个沙盘中运行一样:它们得到了需要支持的模块,而且与外部代码相隔离。
  • 相关阅读:
    欢庆入住博客园
    指定线程所运行的CPU核心
    [GNU/Linux MakeFile] 第一章:概述
    [.NET][编程之美][1.1]C# 实现让CPU占用率曲线听你的指挥 – 可指定运行核心
    vmware workstation 7.1 正式版 序列号 注册机
    linux:设置 linux定时运行命令脚本 (crontab详解)
    守护进程(Daemon)
    Linux下定时执行脚本
    二叉树的遍历(转)
    dup,dup2,fcntl,ioctl用法简述
  • 原文地址:https://www.cnblogs.com/Bryran/p/3976146.html
Copyright © 2011-2022 走看看