第四节:命名空间

(转自老惠的博客

 

当系统大了、程序复杂了、写的人多了,名字的问题就是个大问题。目前来说,解决名字问题的最好办法就是命名空间。

 

使用命名空间,可以避免变量或对象名称产生的冲突,同时,也有助于组织代码,有更强的可维护性和可读性。

 

JavaScript不提供原生的命名空间支持,但我们可以利用JavaScript的一些语言特性,实现类似的效果。

 

1.闭包

 

简单的说,闭包就是,一个函数可以使用函数之外定义的变量,那么这个函数就是闭包。

 

var msg = "你好,朋友";

function sayHello() {

  alert(msg);

}

sayHello();

 

这就是一个最简单的闭包实例。函数sayHello调用了函数外部定义的变量msg,所以函数sayHello就是闭包。

 

function extfunc() {

    var n = 1;

    function internal_func(){

        alert(n++);

    }

    return internal_func();

}

extfunc();

 

这个例子稍微复杂一些,其内部函数(internal_func )是一个闭包,因为它使用外部函数的变量n的值。extfunc()的最后一步调用了internal_func(),增加了变量n的值,并打印它。

 

通过闭包可以让函数内部变量的值始终保持在内存中。比如下面的例子,函数fn()无论执行多少次,其内部变量n的值都是1,因为函数每次执行的时候都会重新分配内存,并初始化其内部变量,而且执行完毕,会释放函数内部变量的内存。

 

function fn() {

    var n = 1;

    alert(n++);

}

fn();

fn();

fn();

 

现在,我们用闭包做一些处理。

 

function fn() {

    var n = 1;

    function in_fn(){

        alert(n++);

    }

    return in_fn;

}

var f = fn();

f();

f();

f();

 

我们发现,每次执行,函数fn()内部的变量n的值都会加一,说明变量n的值始终保存在内存中了。

 

这个例子中,函数fn()最后返回了闭包函数in_fn(),也就是说var f=fn()执行后,f其实是函数in_fn()的引用,此时,函数实例fn()在f引用销毁之前不会销毁,所以,其内部变量n可以保存在内存中。

 

2.自调用匿名函数

 

自调用匿名函数,或者说,立即执行函数表达式,英文缩写IIFE,是一个立即执行的匿名函数表达式,我们把这种代码结构称为“自调用匿名函数”。

 

(function() {

    alert("我是一个自调用匿名函数");

})();

 

该代码定义了一个匿名函数,而且会立即执行。其实,这段代码等同于下面的代码,但这种表达方式更加简单直接。

 

function fn(){

    alert("我是一个自调用匿名函数");

};

fn();

 

下面的方式也是合法的。

 

(function(){

    alert("我是一个自调用匿名函数");

}());

 

当然,自调用匿名函数是可以带参数的。

 

(function(window){

    window.msg = "我被自调用匿名函数初始化";

})(window);

alert(window.msg);

这里,自调用匿名函数执行的时候,将window对象传给了它,它给window对象设置了一个属性msg,并初始化。

 

很明显的是,对于自调用匿名函数,我们不能调用两次,因此,它非常适合做一次性或者初始化性质的工作。

 

要特别注意的是,自调用匿名函数用在赋值函数表达式中的情况。先看下面的例子。

 

var fn = function(){

    return "这是函数执行结果";

}

alert(fn);

 

其fn是一个赋值函数,我们打印出来的是函数的代码:

 

var fn = function(){

    return "这是函数执行结果";

}();

alert(fn);

 

这时候fn就不是一个函数的地址了,而是匿名函数执行后的结果:

 

 

3.命名空间

 

因此,我们可以通过函数作用域来实现JavaScrpt的命名空间 ,也就是利用自调用匿名函数,创建一个特殊的函数作用域,将该作用域中的代码和外界隔离开,从而实现命名空间的概念。

 

比如JQuery框架的命名空间:

 

(function(window,undefined){

     var jQuery = (function(){

          var jQuery = function(){

               alert("创建JQuery对象");

          };

          return jQuery;

     })();

     window.jQuery = window.$ = jQuery;

})(window);

 

执行$(),或者jQuery(),显示:

 

该代码通过自调用匿名函数创建了一个和外界隔离的对象jQuery,并通过全局变量$(window.$)和jQuery(window.jQuery)对外公开,其jQuery对象起到了命名空间的作用。同时利用闭包的特性,让命名空间对象的值始终保持在内存中。

 

4.模块化

 

虽然我们通过JavaScript的闭包、自调用匿名函数等特性,创建了命名空间,或者说我们创建了命名空间模式,可以很好地解决名字问题。但随着系统的增大,需要团队协作完成一个项目,此时,多文件就是必须的了。多文件开发环境下,模块化编程就是我们必须要掌握的一项技术。

 

我们可以通过扩展模式,来实现多人、多文件开发。比如,A定义了一个命名空间Module_A,为了表述的统一,这里我们称为模块Module_A。

 

(function(){

    var Module = {};

    Module.moduleProperty = "模块Module_A的原始属性moduleProperty";

    Module.moduleMethod = function () {

        alert("模块Module_A的原始方法moduleMethod");

    };

    window.Module_A = Module;

})();

 

该代码写在文件file_a.js中。现在,B要负责Module_A模块其他方法的实现,他可以在文件file_b.js中,通过扩展模式,给Module_A添加方法、或者属性。

 

(function(Module){

    Module.anotherMethod = function () {

            alert("模块Module_A的扩展方法anotherMethod");

        };

})(window.Module_A);

 

下面,我们用一个测试文件测试一下:

 

<!doctype html>

<html lang="en">

 <head>

  <meta charset="UTF-8">

  <script src="file_a.js"></script>

  <script src="file_b.js"></script>

  <title>Document</title>

 </head>

 <body>

<script type="text/javascript">

Module_A.moduleMethod();

Module_A.anotherMethod();

</script>

 </body>

</html>

 

很好,运行顺利:

     

但是,如果我们对file_a.js和file_b.js两个文件的引用顺序错了的话,就会产生错误。

错误的原因是我们在扩展Module_A时,Module_A还没有定义,也就是还不存在。这个问题可以通过宽模式扩展解决。

 

file_a.js文件代码的修改:

 

(function(Module){

    Module.moduleProperty = "模块Module_A的原始属性moduleProperty";

    Module.moduleMethod = function () {

        alert("模块Module_A的原始方法moduleMethod");

    };

    window.Module_A = Module;

})(window.Module_A || {});

 

file_b.js文件代码的修改:

 

(function(Module){

    Module.anotherMethod = function () {

        alert("模块Module_A的扩展方法anotherMethod");

    };

    window.Module_A = Module;

})(window.Module_A || {});

 

也就是说,我们在给自调用匿名函数传递参数的时候,就判断全局变量是否存在,如果不存在则直接创建一个Object对象给它。这样,我们就可以可以创建灵活多变的模块,可以将他们无顺序加载,以宽松的方式扩展。

转载于:https://www.cnblogs.com/huiyong/p/7262611.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值