在JS中创建一个对象是非常简单的,可以利用直接量 var object={},也可以用constructor var object = new Object().而且它本身没有特殊的语法,像什么命名空间,modules, packages, private properties和static members.在下面的内容中将会集中展示,命名空间模式,依赖声明,module模式和sandbox模式,它们可以帮助你更好的组织你的代码。
Namespace Pattern
namespace可以帮助我们的程序尽力减少对全局变量的污染,这样我们就可以把命名冲突减小到最低。当然javascript并没有提供原生的支持,就是说并没有像其他语言中直接有声明namespace的语法。不过,我们可以很轻松的来实现它,我们可以声明一个object,然后把所有用到的方法全部加入进来。
//我们来看如何把5个global,缩成一个 //constructors function Parent(){} function Child(){} var some_var=1; //some objects var module1 ={}; module1.data ={a:1, b:2} var module2={} //一个global object var MYAPP = {}; //constructors MYAPP.Parent = function() {}; MYAPP.Child=function(){}; MYAPP.modules={}; MYAPP.modules.module1={}; MYAPP.modules.module1.data={a:1, b:2}; MYAPP.modules.module2={}
上面的代码展示了如何将5个global varibale变成一个.
上述代码可以很好的来避免了全局变量的冲突,但是还会存在着许多的不足:
sandbox模式可以避免上述缺点.
Declaring Dependencies
javascript库一般是modular和namespaced.这意味着你可以只加载你想要的modules.例如YUI,这里只有一个global的全局变量YAHOO,但是有许多的module,比如DOM Module: YAHOO.util.Dom, Event Module:YAHOO.util.Event
var myFunction = function(){ var event = YAHOO.util.Event, dom = YAHOO.util.DOM; }
尽管上述代码只是很简单的pattern,但是却有很多好处:
Private Properties and Methods
在Javascript中object中的所有成员都是public的.
private Members:
我们可以借助于closure来实现private members.
function Gadget(){ //private member var name = 'iPod'; //public function this.getName = function(){ return name; } } var toy = new Gadget(); //'name' is undefined, it's private console.log(toy.name);//undefined console.log(toy.getName();//'iPod'
Object Literals and Privacy
var myobj;//this will be the object (function(){ //private members var name ="my, oh my"; myobj = { getName : function() { return name; }; }; }()); myobj.getName();//"my, oh my"
Prototypes and Privacy
function Gadget(){ //private members var name ='iPod'; //public function this.getName = function() { return name; } } Gadget.prototype = (function(){ //private member var browser = 'Mobile Webkit'; return { getBrowser: function(){ return browser; } } }()); var toy = new Gadget(); console.log(toy.getName());//privileged "own" method console.log(toy.getBrowser());//privileged prototype method
Module Pattern
module可以给我们提供一种更好的组织代码的方式来面对日益增长的code.来看下面的code,我们首先建立一个namespace,然后定义一个局部变量,然后把我们的那些公共方法以一个object的形式来返回。
//首先声明一个命名空间 MYAPP.namespace("MYAPP.utilities.array'); //以immediate execute的方式返回一个object MYAPP.utilities.array = (function(){ //声明依赖的函数 var uobj = MYAPP.utilities.object, ulang = MYAPP.utilities.lang, //声明private properties array_string = "[objects Array]", ops = Object.prototype.toString; //private methods //... //返回public API return { inArray: function(needle, haystack){ for(var i=0, max = haystack.length; i<max; i+=1){ if(haystack[i] === needle){ return true; } } }, isArray: function(a){ return ops.call(a) === array_string; } }; }());
用构造函数来创造module的模式
也许有的时候,我们更想要用到构造函数来创造一个新的对象
//首先声明一个命名空间 MYAPP.namespace("MYAPP.utilities.array'); //以immediate execute的方式返回一个object MYAPP.utilities.array = (function(){ //声明依赖的函数 var uobj = MYAPP.utilities.object, ulang = MYAPP.utilities.lang, //声明private properties Constr; array_string = "[objects Array]", ops = Object.prototype.toString; //private methods //... //返回public API Constr = function(o){ this.elements = this.toArray(o); } //public API -- prototype Constr.prototype = { constructor: MYAPP.utilities.Array, version: '2.0', toArray: function(obj){ for(var i=0, a=[], len = obj.length; i<len; i++){ a[i] = obj[i]; } return a; } } return Constr; }());
如果我们想要上边的对象,我们可以用var arrObj = new MYAPP.utilities.Array(obj);
Sandbox Pattern
sandbox可以解决namesapceing pattern的一些缺点:
如果用sandbox我们以传给它的构造函数一个callback function, 这样的话就相当于我们提供了一个单独封闭的环境给你的code
new Sandbox(function(box){
your code here.
});
这个模式还需要加入两个feature
就像这样: Sandbox(['ajax','event'], function(box){
//我们依赖于ajax, event这两个object
});
如何构建Sandbox构造函数:
//下面新添的两个只是为了对后面的constructor代码起一个帮助的作用,如果想看更好的实现推荐requirejs Sandbox.modules = {}; Sandbox.modules.dom = function(box) { box.getElement = function() {}; box.getStyle = function() {}; box.foo = "bar"; } Sandbox.modules.event = function(box) { box.attacheEvet = function() {}; box.dettachEvent = function() {}; }; //Implementig the Constructor function Sandbox(){ var args = Array.prototype.slice.call(argumentss),//首先把arguments转化为数组,看后面的pop函数 callback = args.pop(), //对于modules,我们可以以一个字符串的形式,也可以传入一个数组。 modules = (args[0] && typeof args[0] === 'string') ? args : args [0]; i;//介这是为后边遍历用的 //下面的代码,保证了我们如果不用new,也会返回一个object if(!(this instanceof Sandbox)){ return new Sandbox(modules, callback); } //我们可以加入一些属性,如果有必要 this.a =1; this.b = 2; //好的我们把一些需要的module加入到this object //如果是‘*’或者是没有modules, 我们 if(!modules || modules ==='*'){ moduels = []; for( i in Sandbox.moduels){ if(Sandbox.modules.hasOwnProperty(i)){ moduels.push(i); } } } //初始化这些我们需要的moduels,就是类似于我们可以用this.event, this.dom我们已经在上面的 for( i=0; i < modules.length; i+=1){ Sandbox.moduels[moduels[i]](this); } //把this传入到callback中 callback(this); } //添加一些
PublicStatic members
//constructor var Gadget = function() {}; Gadget.isShiny = function() { return "you bet"; }; //注意我们只能通过构造函数来调用这个函数 Gadget.isShiny();//you bet
Private Static Members
直接看代码
var Gadget = (function(){ //static varibable/property var counter = 0; //returning the new implementation return function(){ console.log(counter+=1); } }()); var g1 = new Gadget();//log1 var g2 = new Gadget();//log2 var g3 = new Gadget();//log3