日期:2014-05-16  浏览次数:20278 次

JavaScript类库/组件/框架封装的总体结构

之前也有封装过简单的Javascript组件,但是因为没有遵循和参考过好的编码原则,封装的方式有诸多不妥。最近参考了几个框架的源代码解析,加上自己的理解,总结成文供以后参考。

笔者认为,所谓类库(或称框架)通常就是一个闭包,这个闭包可以访问外部宿主函数中定义的一些对外不可见的方法和变量,而对外提供的方法则放在类库的原型prototype中。关于闭包的概念,详见笔者的《深入理解JavaScript闭包》。类库对外提供一个初始化的入口,用于构造实例对象,此时宿主函数就是实例的作用域。由于类库的内部实现对外界是透明的,其内部变量不对外部全局变量造成影响,具有很好的封装性。

整个类库代码最外层应该是一个“自调用匿名函数”,匿名函数作为类库闭包的宿主函数,创建了一个“私有”的命名空间,最后通过将类库闭包赋值给Global对象window,将其暴露给最外层的全局作用域。先来看一下JQuery代码的总体结构:

(function( window, undefined ) {
    var jQuery = (function(p1,p2) {
        // jquery code
        return new jQuery.fn.init(p1,p2,p3);
    });
    window.jQuery = window.$ = jQuery;
})(window);


之所以要传入window变量,是为了使window由全局变量变为局部变量,当在jQuery代码块中访问window时,不需要将作用域链回退到顶层作用域,这样可以更快的访问window;更重要的是,将window作为参数传入,可以在压缩代码时进行优化,看看jquery-1.x.x.min.js:

(function(a,b){})(window); //window被优化为a,undefined被优化为b

在参数列表中增加undefined的原因,应该主要也是为了便于最大程度的压缩代码;纵观jquery原始的未压缩代码,里面有很多地方引用了window和undefined变量,将二者作为参数引入并进行压缩是非常值得的。

总的来说,JavaScript类库比较流行的总体结构就是:1、“自调用匿名函数”封装并运行类库的所有代码,将类库的接口暴露给全局作用域;2、用原型prototype给类库的实例提供方法。剩下的就是细节问题了~