有关 JavaScript 编程思想中命名空间的思考

JavaScript编程思想,这个编程思想挺伟大的词在我的心里其实很纠结。JavaScript 命名空间的资料在网上一搜一大把,本人只是做个学习的小结。

网上常见的代码,都常见得快烂透了,因为方便+简单嘛:

var GLOBAL = {
    str: 'linkClass',
    init: function(){
        return str;
    }
};

上面也是本人受前端牛人指点时的经典代码。经典到前段时间我才从中走出来。

不想固步自封?那就下一步了。不过,在下一步之前先看与之等价的代码:

var GLOBAL = {};
GLOBAL.str='linkClass';
GLOBAL.init=function(){
    return str;
};

呃,因为只要会写JavaScript,都会上面的了(瞧瞧这哥们写的)。那么这下一步其实还是等价的代码:

var GLOBAL = {};
GLOBAL['str']='linkClass';
GLOBAL['init']=function(){
    return str;
};

问题是上面的对象中的属性和方法没有达到松耦合,一直都还没有实现面向对象最最基本的封装特性。你看str属性其实不必给暴露出来,因为init方法的作用就是返回str的值。所以:

(function(){
var str='linkClass';
function init(){
    return str;
}
window['GLOBAL']={};
window['GLOBAL']['init']=init;
})();

这样写的好处解释下:在命名空间下定义的属性或方法是全局的,也就是等于暴露出去的接口,而私用变量在 JavaScript 闭包外是无法 get 和 set 的。str 从函数 init 内找起,然后沿着作用域链找到了它。也达到了松耦合。

松耦合的概念我是在Yahoo前端从库往框架走的这么一个“理念”中看到的。

所以,从这段代码的来源中学习后就震撼了,上面我的解释挺民科的,下面摘录《JavaScript 权威指南(第5版)》中8.8.2节的内容:

It is sometimes useful to define a function simply to create a call object that acts as a temporary namespace in which you can define variables and create properties without corrupting the global namespace. Suppose, for example, you have a file of JavaScript code that you want to use in a number of different JavaScript programs (or, for client-side JavaScript, on a number of different web pages). Assume that this code, like most code, defines variables to store the intermediate results of its computation. The problem is that since this code will be used in many different programs, you don't know whether the variables it creates will conflict with variables used by the programs that import it.

The solution, of course, is to put the code into a function and then invoke the function. This way, variables are defined in the call object of the function:

function init() {
    // Code goes here.
    // Any variables declared become properties of the call
    // object instead of cluttering up the global namespace.
}
init();  // But don't forget to invoke the function!

The code adds only a single property to the global namespace: the property "init", which refers to the function. If defining even a single property is too much, you can define and invoke an anonymous function in a single expression. The code for this JavaScript idiom looks like this:

(function() {  // This function has no name.
    // Code goes here.
    // Any variables declared become properties of the call
    // object instead of cluttering up the global namespace.
})();          // end the function literal and invoke it now.

Note that the parentheses around the function literal are required by JavaScript syntax.

hax说,IE有全局变量DID(人格分裂症)。所以,请慎用!另外,这不是所谓的“JS分层概念”。

更新于 2010.1.29

另一种方法是用函数作为命名空间,请见 David 原文《Functions as Namespaces, and How to Peek Inside》及译文《如何访问作为命名空间的函数内部变量》。

posted on 2009-11-23 17:18  豆豆の爸爸  阅读(955)  评论(0编辑  收藏  举报