Javascript Patterns--读书笔记5 (Object Creation Patterns)

在JS中创建一个对象是非常简单的,可以利用直接量 var object={},也可以用constructor var object = new Object().而且它本身没有特殊的语法,像什么命名空间,modules, packages, private properties和static members.在下面的内容中将会集中展示,命名空间模式,依赖声明,module模式和sandbox模式,它们可以帮助你更好的组织你的代码。

Namespace Pattern

namespace可以帮助我们的程序尽力减少对全局变量的污染,这样我们就可以把命名冲突减小到最低。当然javascript并没有提供原生的支持,就是说并没有像其他语言中直接有声明namespace的语法。不过,我们可以很轻松的来实现它,我们可以声明一个object,然后把所有用到的方法全部加入进来。

View Code
//我们来看如何把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变成一个.

上述代码可以很好的来避免了全局变量的冲突,但是还会存在着许多的不足:

  • 名字太长,我们需要键入太多的代码,这意味着会增大文件,从而浪费加载时间
  • 只有一个总的全局变量,这意味着所有的code都可以来更改这个global,而且其它的部分也会得到这些更改过的状态
  • 太长的命名,意味着花更多的时间来查找每个内嵌的变量

sandbox模式可以避免上述缺点.

Declaring Dependencies

javascript库一般是modular和namespaced.这意味着你可以只加载你想要的modules.例如YUI,这里只有一个global的全局变量YAHOO,但是有许多的module,比如DOM Module: YAHOO.util.Dom, Event Module:YAHOO.util.Event

View Code
var myFunction = function(){
  var event = YAHOO.util.Event,
        dom = YAHOO.util.DOM;
}

 尽管上述代码只是很简单的pattern,但是却有很多好处:

  • 可以很清晰的告诉我们你所依赖的script file是否被引用到page当中。
  • 把声明放在前边可以很清晰的发现和解决依赖。
  • 另外,通过这种方式可以提高效率,我们不需要再去一层层的查找了,例如Yahoo.util.dom,我们可以直接用dom来引用,大幅度的提高代码效率。

Private Properties and Methods

在Javascript中object中的所有成员都是public的.

private Members:

我们可以借助于closure来实现private members.

View Code
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

View Code
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

View Code
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的形式来返回。

View Code
//首先声明一个命名空间
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的模式

也许有的时候,我们更想要用到构造函数来创造一个新的对象

View Code
//首先声明一个命名空间
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的一些缺点:

  • 在namespacing pattern的时候,我们无法解决一个全局变量来引用同一个库的两个版本的问题,因为它们都会依赖于同一个全局变量
  • 很长的用点分隔的名字,因为那样会降低我们的效率。

如果用sandbox我们以传给它的构造函数一个callback function, 这样的话就相当于我们提供了一个单独封闭的环境给你的code

new Sandbox(function(box){

  your code here.

});

这个模式还需要加入两个feature

  • 我们不需要用new 可以来创造 一个新的对象
  • Sandbox()可以接受另外一个configure object,这个object指示明了我们需要的对象。

就像这样: Sandbox(['ajax','event'], function(box){

  //我们依赖于ajax, event这两个object

});

如何构建Sandbox构造函数:

View Code
//下面新添的两个只是为了对后面的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

View Code
//constructor
var Gadget = function() {};

Gadget.isShiny = function() {
return "you bet";
};

//注意我们只能通过构造函数来调用这个函数
Gadget.isShiny();//you bet

 

Private Static Members

直接看代码

View Code
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

 

 

 

 

posted @ 2012-09-20 21:22  moonreplace  阅读(288)  评论(0编辑  收藏  举报