JavaScript之命名空间
来源:互联网 发布:2016淘宝处罚规则 编辑:程序博客网 时间:2024/05/02 04:56
JavaScript之命名空间
使用过Java、C#的同学对命名空间非常的熟悉,在复杂的系统中会有N多的函数、对象,语言提供的、架构预定义的,这么多的函数和对象,由于编程规范要求起有实际意义的名字,难免会重名发生错误调用,而有了命名空间烦恼就没有了,不但可以分类组织函数与对象,还可以形成隔离,解决重名问题。
使用JavaScript就没有这么舒服了,Javascript只有函数作用域,什么块儿啊、神马文件啊统统都认为是一个命名空间的,有时候因为一些重名问题导致的错误让人莫名其妙,难以调试解决。
一个简单的例子
<input type="button" value="test" onclick="alert();"/> <script type="text/javascript"> function alert(){ //....... test2(); //....... } function test2(){ alert('test2') }
在个例子在不同的浏览器下有不同表现,IE会报Stack over flow, Firefox会死掉。。。反正都会报错,很简单的错误,代码中自定义了一个alert函数,在alert函数中调用了test2函数,test2函数中意图调用window的alert方法,这样循环调用了,也许看了你会说这么明显的错误谁会犯,但是如果自定义的方法叫close(这个经常会出现吧),然后内部调用了一个外部文件的函数,该函数调用了window的close方法,这样错误是不是隐蔽了很多呢。
简单的命名空间
由于JavaScript没有文件作用域,不同的函数分散在不同的文件中,甚至由不同的人编写,重名的概率大大增加。是不是足够小心就可以了呢?也不尽然,还有些意外情况,比如经常会用到继承,于是写了一个没出现过的函数名extend,不料在EcmaScript5中加入了extend函数,命名空间的必要性就体现出来了。
JavaScript有函数的作用域,可以利用这点把自定义的函数写到一个函数体内,这样函数内的变量、对象、函数就像在一个命名空间内一样和外部隔离。
<input type="button" value="test" onclick="(new namespace()).alert();"/><script type="text/javascript">function namespace() { this.alert = function () { console.log('test'); }}</script>
这样自定义的alert方法就不会和window的alert冲突了。
简单进化
这样可以是可以,但也有问题,最大的问题在于调用方式复杂而丑陋!每次调用的时候都要实例化对象,然后调用其方法,简单修改代码让其实现自动实例化。
<input type="button" value="test" onclick="NS.alert();"/><script type="text/javascript">(function namespace() { this.alert = function () { console.log('test'); } window.NS = this;})();</script>
要看明白上面代码首先要了解一下“立即执行函数”(江湖人是这么称呼的)的技巧结构类似这样
(function xxx(){
//function body
})();
这样写xxx函数就可以在定义完后自动执行,看起来神奇,其实上面写法可以拆成这样
function xxx(){ //function body }xxx();
就是定义一个函数,然后使用括号语法调用,而函数定义外面的一层括号只起到将函数声明转为函数定义表达式,因为只有表达式才可以使用括号调用。看明白这些妖蛾子之后上面代码就简单了,在自定义namespace函数最后把this赋值为window的NS属性,在调用的时候直接使用NS.xx就可以了。看起来好了很多。
美化一下
上面的写法看起来不错了,但是函数名namespace貌似是多余的了,可以美化一下
(function (){ this.alert=function(){ console.log('test'); } window.NS=this;})();
变成了一个立即执行的匿名函数,美化了一些,不过看起来还是怪怪的,对呀,明明是实例化的function,为什么方法定义不写到prototype中呢,匿名函数怎么写prototype。。。,还得动动脑筋
(function () { var _NS = function () { } _NS.prototype.alert = function () { console.log('test'); } window.NS = new _NS();})();
写几个有用的函数
querySelector和querySelectorAll是W3C提供的新的查询接口,但是名字好长,自己写个简单的,innerHTML属性也常用到,写个简单版仿jQuery的html方法
(function () { var _NS = function () { } _NS.prototype.select = function (selector, context) { var context = context || document; return context.querySelectorAll(selector); } _NS.prototype.isArrayLike = function (obj) { if (obj instanceof Array) { return true; } var length = obj.length; if (obj.nodeType === 1 && length) { return true; } return false; } _NS.prototype.html = function (obj, value) { var isArray = this.isArrayLike(obj), i = 0; if (typeof value == 'string') { if (!isArray) { obj.innerHTML = value; } else { var length = obj.length; while (i < length) { obj[i].innerHTML = value; i += 1; } } } else { if (!isArray) { return obj.innerHTML; } else { return obj[0].innerHTML; } } } window.NS = new _NS();})();
通过函数(function) 创建
这是一种比较常见的写法, 通过声明一个function实现, 函数里设置初始变量, 公共方法写入prototype, 如:
var NameSpace = window.NameSpace || {};/*Function*/NameSpace.Hello = function () { this.name = 'world';};NameSpace.Hello.prototype.sayHello = function (_name) { return 'Hello ' + (_name || this.name);};var hello = new NameSpace.Hello();hello.sayHello();
这种写法比较冗长, 不利于压缩代码( jQuery使用fn代替prototype), 而且调用前需要先实例化( new)。 使用Object写成JSON形式可以写得紧凑些:
通过JSON对象创建Object
/*Object*/var NameSpace = window.NameSpace || {};NameSpace.Hello = { name: 'world', sayHello: function (_name) { return 'Hello ' + (_name || this.name); }};
调用
NameSpace.Hello.sayHello(‘JS’); > Hello JS;
这种写法比较紧凑, 缺点是所有变量都必须声明为公有(public) 的, 导致所有对这些变量的引用都需要加this指示作用域, 写法也略有冗余。
通过闭包(Closure) 和Object实现
在闭包中声明好所有变量和方法, 并通过一个JSON Object返回公有接口:
var NameSpace = window.NameSpace || {};NameSpace.Hello = (function () { //待返回的公有对象 var self = {}; //私有变量或方法 var name = 'world'; //公有方法或变量 self.sayHello = function (_name) { return 'Hello ' + (_name || name); }; //返回的公有对象 return self;}());
Object和闭包的改进型写法
上个例子在内部对公有方法的调用也需要添加self, 如: self.sayHello(); 这里可以最后再返回所有公有接口( 方法 / 变量) 的JSON对象。
var NameSpace = window.NameSpace || {};NameSpace.Hello = (function () { var name = 'world'; var sayHello = function (_name) { return 'Hello ' + (_name || name); }; return { sayHello: sayHello };}());
Function的简洁写法
这是一种比较简洁的实现, 结构紧凑, 通过function实例, 且调用时无需实例化( new), 方案来自stackoverflow:
var NameSpace = window.NameSpace || {};NameSpace.Hello = new function () { var self = this; var name = 'world'; self.sayHello = function (_name) { return 'Hello ' + (_name || name); };};
调用
NameSpace.Hello.sayHello();
- JavaScript之命名空间
- JavaScript之命名空间模式
- JavaScript之命名空间模式 浅析
- Javascript面向对象之命名空间问题
- Javascript命名空间
- javascript 命名空间
- javascript 命名空间
- javascript 命名空间
- javascript命名空间
- Javascript中的命名空间
- javascript 命名空间
- javaScript 命名空间
- JavaScript命名空间
- javascript命名空间写法
- javascript命名空间
- javascript 命名空间
- JavaScript 命名空间
- JavaScript命名空间
- Innodb中的事务隔离级别实现原理
- vs打包工具
- Linux目录详情
- 数据结构之有向图
- linux下生成静态库和动态库
- JavaScript之命名空间
- JAVA代码优化
- Android开发-RecyclerView-AndroidStudio(四)属性动画(1)RemoveDuration
- codevs 2594 解药还是毒药(状态压缩BFS)
- 百度面试问题总结
- 运放参数解释及常用运放选型
- Scikit Learn简介
- 《合成孔径雷达成像——算法与实现》之【5】仿真图3.6
- ida unicode/utf-16识别脚本