标签:
当我们以一个通常的写法来写一个构造函数的时候(通过new 调用的函数) 它里面的属性和方法对外界是可见的
function Person() { this.name = "haha"; this.sayName = function(){ return this.name; }
return this; } var p1 = new Person(); console.log(p1.sayName());//haha console.log(p1.name);//haha
p1.name = ""ha";
console.log(p1.sayName());//ha
这里的Person定义了一个name属性和一个sayName方法 通过生成的对象能调用相应的方法 但是发现生成的对象也能直接调用name属性(这并没有任何奇怪 因为name本身就是生成对象的属性) 这样的模式不能达到我们实现私有属性的目的
要实现私有属性 ,就要通过匿名闭包
(function(){ //所用的变量和function都在这里声明,作用域也只能存在这个闭包中,这里的代码仍然能访问外部的作用域,是作用链的问题 }());
我们在匿名闭包中声明变量和function 这样作用域只存在这个闭包中,外界无法访问 ,但是这里的代码可以通过作用链查找到外面的变量
下面我们来实现一个简单的例子(简单的module模式)
var module = (function(){ var my = {}, id = 123; function getId() { return id; }//私有变量和function在这里声明,在外边是不能访问到的 my.Id = id; my.getPrivateId = function() { return getId(); } return my; //只能通过返回的my来访问内部的私有变量和function }()); console.log(module.Id); console.log(module.getPrivateId());
当我们有新的需求要扩展我们的module的时候(项目组的好几个人都要扩展) 首先他要引入之前的module文件 也就是上面这段例子,然后在进行扩展(这样也实现了module的多人开发)
var module = (function(my){ my.say = function() { return "扩展了"; } return my; }(module)); console.log(module.say()); //扩展了
这里实现的方式是将之前的module传入匿名闭包函数 ,对它的相应的功能进行添加,同时还是保持了之前私有变量和function的私有性,这里的var并不是必须的(因为之前已经声明了module 这是一种紧耦合的扩展模式),这种模式对文件的加载顺序有要求
如果不对文件的加载顺序有要求,也就是松耦合的扩展模式 可以这样实现
var module = (function(my){ //扩展 return my; }(module || {}))
当我们为匿名闭包传递参数的时候传递的是 module || {} 也就是当module不存在的时候 ,我们去创建它 这就不需要我们文件的加载顺序有要求了,这是一种松耦合的扩展模式,这种模式下也有一定的限制,就是不能重写一些属性和方法 (因为不用加载顺序,当我们想重写的时候,相应的属性和方法有可能不存在,就不存的重写这个说法,也就是新的定义)并且这里的var必须写,(因为其他的人想读取你的文件的时候会读取不到)
紧耦合的模式下虽然限制了加载的顺序,但是能提供给我们重写属性方法的机会
var module = (function(){ var my = {}; var id = 123; function a() { return "a"; }; my.b = function(){ return "this is old func"; } return my; }()); console.log(module.b());//this is old func var module = (function(my){ var oldfunc = my.b; my.b = function() { return "this is new func"; } my.oldfunc = oldfunc; return my; }(module)); console.log(module.b()); //this is new func console.log(module.oldfunc());//this is old func
上面是一个完成了例子 重写了之前定义的b方法 并且通过将之前的方法重新添加到module中,也可以访问之前的方法
子模块实现方式 当我们需求在上面的module下实现一个子模块的时候 我们可以这样
module.test = (function(){ var name = "aa", my = {}; my.sayName = function(){
//console.log(mudule.b()); //子模块能调用父模块的方法 他们在一个命名空间 return name; } return my; }()); console.log(module.test.sayName());//aa
这样就实现了一个子模块
在javascript设计模式的书中,提供了一种创建命名空间的方式,上面的创建子模块的方式 子模块和父模块存在一个命名空间(有些时候我们想要实现的是两个module存在不同的命名空间 ) 下面给出书中的实现方式
首先我们需要一个创建命名空间的通用函数
var MySpace = MySpace || {}; MySpace.namespace = function(ns_string){ var parts = ns_string.split(‘.‘), parent = MySpace, i = 0, length = 0; if(parts[0] === "MySpace") { parts = parts.slice(1); } for(i = 0;length = parts.length,i < length;i += 1) { if(typeof parent[parts[i]] === "undefined") { parent[parts[i]] = {}; } parent = parent[parts[i]]; } return parent; }
通过上面的函数我们就能在相应的命名空间里创建我们的module了
MySpace.namespace(‘MySpace.modules.test‘); MySpace.modules.test = (function(){ var name = "haha", my = {}; my.sayName = function(){ return name; } return my; }());
MySpace.namespace(‘MySpace.modules.a‘);//在同样的层级创建其他的module
参考 javascript设计模式
blog http://www.cnblogs.com/TomXu/archive/2011/12/30/2288372.html
标签:
原文地址:http://www.cnblogs.com/tiantianwaigong/p/4777266.html