在JavaScript中创建对象是非常简单的,你可以使用对象字面量(object literal)或者使用构造函数(方法)(constructor)。
在这章里,我们会超出这些,看到一些额外的对象创建模式。
JavaScript语言是简单而直接的,通常没有特别的语法实现你在其它语言中使用的功能,比如命名空间(namespaces)、模块(modules)、包(packages),私有属性(private properties)和静态变量(static members)。接下来,我们会去实现这些常见的模式,或者使用其他方式代替,或者比较二者的不同。
我们会看到命名空间(namespacing),依赖声明(dependency declaration),模块模式(module pattern)和沙箱模式(sandbox patterns),这些会帮助组织和构建你的程序代码并且减少潜在的全局变量。讨论的主题还包括private或者享有特权(privileged)的成员变量,static或者private static的成员,对象常量,链式编程,使用特殊的方法的构造函数。
// BEFORE: 5 globals // Warning: antipattern // constructors function Parent() {} function Child() {} // a variable var some_var = 1; // some objects var module1 = {}; module1.data = {a: 1, b: 2}; var module2 = {};你可以重构这种类型的代码通过为你的程序创建一个全局对象,比如叫做:MYAPP,并且将你所有的函数和变量作为这个全局变量的属性:
// AFTER: 1 global // global object var MYAPP = {}; // constructors MYAPP.Parent = function () {}; MYAPP.Child = function () {}; // a variable MYAPP.some_var = 1; // an object container MYAPP.modules = {}; // nested objects MYAPP.modules.module1 = {}; MYAPP.modules.module1.data = {a: 1, b: 2}; MYAPP.modules.module2 = {};对于全局命名空间对象的名字,你可以选择你的程序或者类库的名字,你的域名,或者公司的名字。通常程序猿都会遵循约定,全局变量名全大写,所以更容易被代码的读者发现。(但也要记住全部大写通常也被用来命名常量)
// unsafe var MYAPP = {}; // better if (typeof MYAPP === "undefined") { var MYAPP = {}; } // or shorter var MYAPP = MYAPP || {};你可以看到这些添加的检查会很快导致大量重复代码。比如:如何你想定义MYAPP.modules.module2,你讲不得不进行三次检查,每个你定义的属性或对象都需要一次;
// using a namespace function MYAPP.namespace('MYAPP.modules.module2'); // equivalent to: // var MYAPP = { // modules: { // module2: {} // } // };接下来的例子是命名空间函数的实现。这个实现是非破坏性的,意味着如何一个命名空间已经存在,那么它不会被重新创建:
var MYAPP = MYAPP || {}; MYAPP.namespace = function (ns_string) { var parts = ns_string.split('.'), parent = MYAPP, i; // strip redundant leading global if (parts[0] === "MYAPP") { parts = parts.slice(1); } for (i = 0; i < parts.length; i += 1) { // create a property if it doesn't exist if (typeof parent[parts[i]] === "undefined") { parent[parts[i]] = {}; } parent = parent[parts[i]]; } return parent; };这个实现可以这样使用:
// assign returned value to a local var var module2 = MYAPP.namespace('MYAPP.modules.module2'); module2 === MYAPP.modules.module2; // true // skip initial `MYAPP` MYAPP.namespace('modules.module51'); // long namespace MYAPP.namespace('once.upon.a.time.there.was.this.long.nested.property');