Sandbox mode is commonly seen in YUI3 core. It is a method that uses the same constructor (Constructor) to generate instance objects that are independent of each other and do not interfere with each other (self-contained), thereby avoiding contamination of the global object.
Namespace
JavaScript itself does not provide a namespace mechanism, so in order to avoid contamination of the global space by different functions, objects, and variable names, the usual approach is to create a unique global object for your application or library, and then Add all methods and properties to this object.
Code Listing 1: Traditional namespace mode
/* 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 = {};
In this code, you create a global object MYAPP and attach all other objects and functions to MYAPP as attributes.
Usually this is a better way to avoid naming conflicts and it is used in many projects, but this method has some disadvantages.
You need to add prefixes to all functions and variables that need to be added.
Because there is only one global object, this means that part of the code can modify the global object arbitrarily and cause the rest of the code to be passively updated.
Global constructor
You can use a global constructor instead of a global object. We name this constructor Sandbox(). You can use this constructor to create objects. You can also pass a The callback function is used as a parameter. This callback function is an independent sandbox environment where you store your code.
Code Listing 2: Usage of Sandbox
new Sandbox(function(box){ // your code here... });
Let us add some other features to the sandbox.
You can create a sandbox without using the 'new' operator.
The Sandbox() constructor accepts some additional configuration parameters, which define the names of the modules required to generate the object. We want the code to be more modular.
After having the above features, let us see how to initialize an object.
Code Listing 3 shows that you can create an object that calls the 'ajax' and 'event' modules without the need of the 'new' operator.
Code Listing 3: Passing the module name as an array
Sandbox(['ajax', 'event'], function(box){ // console.log(box); });
Code Listing 4: Passing the module name as a separate parameter
Sandbox('ajax', 'dom', function(box){ // console.log(box); });
Code Listing 5 shows that you can pass the wildcard '*' as a parameter to the constructor, This means calling all available modules. For convenience, if no module name is passed to the constructor as an argument, the constructor will pass '*' as the default argument.
Code Listing 5: Calling the available modules used
Sandbox('*', function(box){ // console.log(box); }); Sandbox(function(box){ // console.log(box); });
Code Listing 6 shows that you can initialize the sandbox object multiple times, and you can even nest them without worrying about any conflicts with each other.
Code Listing 6: Nested Sandbox Instance
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 });
As you can see from the above examples, using the sandbox mode, by wrapping all code logic in a callback function, you can generate different modules based on the required modules. Instances, and these instances work independently without interfering with each other, thereby protecting the global namespace.
Now let’s see how to implement this Sandbox() constructor.
Adding Modules
Before implementing the main constructor, let’s see how to add modules to the Sandbox() constructor.
Because the Sandbox() constructor function is also an object, you can add an attribute named 'modules' to it. This attribute will be an object containing a set of key-value pairs, where the Key of each pair is The name of the module that needs to be registered, and Value is the entry function of the module. When the constructor is initialized, the current instance will be passed to the entry function as the first parameter, so that the entry function can add additional properties and methods to the instance.
In code listing 7, we added the 'dom', 'event', and 'ajax' modules.
Code Listing 7: Registration module
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() {}; };
Implementing the constructor
Code Listing 8 describes the method of implementing the constructor, with several key points:
We check whether this is an instance of Sandbox, if not, prove Sandbox If it is not called by the new operator, we will call it again as a constructor.
You can add attributes to this inside the constructor, and you can also add attributes to the prototype of the constructor.
The module name will be passed to the constructor in various forms such as arrays, independent parameters, and the wildcard character '*'.
Please note that in this example we do not need to load modules from external files, but in systems such as YUI3, you can only load the base module (often called a seed), and all other modules will be loaded from external files. loaded in the file.
一旦我们知道了所需的模块,并初始化他们,这意味着调用了每个模块的入口函数。
回调函数作为参数被最后传入构造器,它将使用最新生成的实例并在最后执行。
代码清单8:实现Sandbox构造器
<script> 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; } }; </script>